knife-ovh 0.0.2

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.
@@ -0,0 +1,111 @@
1
+ #
2
+ # Author:: Alexis Gruet (<alexis.gruet@kroknet.com>)
3
+ #
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+
7
+ require 'chef/knife'
8
+ require 'rbvmomi'
9
+
10
+ # Base class for vsphere knife commands
11
+ class Chef
12
+ class Knife
13
+ module OvhBase
14
+
15
+ # :nodoc:
16
+ # Would prefer to do this in a rational way, but can't be done b/c of
17
+ # Mixlib::CLI's design :(
18
+ def self.included(includer)
19
+ includer.class_eval do
20
+
21
+ deps do
22
+ require 'socket'
23
+ require 'net/ssh/multi'
24
+ require 'readline'
25
+ require 'chef/json_compat'
26
+ end
27
+
28
+ option :vsphere_user,
29
+ :short => "-u USERNAME",
30
+ :long => "--user USERNAME",
31
+ :description => "The username for the host"
32
+
33
+ option :password,
34
+ :short => "-p PASSWORD",
35
+ :long => "--password PASSWORD",
36
+ :description => "The password for the host"
37
+
38
+ option :datacenter,
39
+ :short => "-d DATACENTER",
40
+ :long => "--datacenter DATACENTER",
41
+ :description => "The Datacenter to create the VM in"
42
+
43
+ option :path,
44
+ :long => "--path SOAP_PATH",
45
+ :description => "The SOAP endpoint path",
46
+ :proc => Proc.new { |p| Chef::Config[:knife][:path] = p },
47
+ :default => "/sdk"
48
+
49
+ option :port,
50
+ :long => "--port PORT",
51
+ :description => "The VI SDK port number to use",
52
+ :proc => Proc.new { |p| Chef::Config[:knife][:port] = p },
53
+ :default => 443
54
+
55
+ option :use_ssl,
56
+ :long => "--ssl USE_SSL",
57
+ :description => "Whether to use SSL connection",
58
+ :default => true
59
+
60
+ option :insecure,
61
+ :short => "-i USE_INSECURE_SSL",
62
+ :long => "--insecure USE_INSECURE_SSL",
63
+ :description => "Determines whether SSL certificate verification is skipped",
64
+ :default => true
65
+ end
66
+ end
67
+
68
+ def get_vim_connection
69
+
70
+ conn_opts = {
71
+ :host => config[:host] || Chef::Config[:knife][:vsphere_host],
72
+ :path => config[:path],
73
+ :port => config[:port],
74
+ :use_ssl => config[:ssl],
75
+ :user => config[:vsphere_user] || Chef::Config[:knife][:vsphere_user],
76
+ :password => config[:password] || Chef::Config[:knife][:vsphere_pass],
77
+ :insecure => config[:insecure]
78
+ }
79
+
80
+ vim = RbVmomi::VIM.connect conn_opts
81
+
82
+ return vim
83
+ end
84
+
85
+ def get_folders(folder)
86
+ folder.childEntity.grep(RbVmomi::VIM::Folder) << folder
87
+ end
88
+
89
+ def find_all_in_folders(folder, type)
90
+ get_folders(folder).
91
+ collect { |f| f.childEntity.grep(type) }.
92
+ flatten
93
+ end
94
+
95
+ def find_in_folders(folder, type, name)
96
+ get_folders(folder).
97
+ collect { |f| f.childEntity.grep(type) }.
98
+ flatten.
99
+ find { |o| o.name == name }
100
+ end
101
+
102
+ def fatal_exit(msg)
103
+ ui.fatal(msg)
104
+ exit 1
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,39 @@
1
+ #
2
+ # Author:: Alexis Gruet (<alexis.gruet@kroknet.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+
6
+ require 'chef/knife/ovh_base'
7
+
8
+ # Lists all known VM templates in the configured datacenter
9
+ class Chef
10
+ class Knife
11
+ class OvhPccTemplateList < Knife
12
+
13
+ include Knife::OvhBase
14
+
15
+ banner "knife ovh pcc template list"
16
+
17
+ def run
18
+
19
+ $stdout.sync = true
20
+ $stderr.sync = true
21
+
22
+ vim = get_vim_connection
23
+
24
+ dcname = config[:vsphere_dc] || Chef::Config[:knife][:vsphere_dc]
25
+ dc = vim.serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
26
+
27
+ vmFolders = get_folders(dc.vmFolder)
28
+
29
+ vms = find_all_in_folders(dc.vmFolder, RbVmomi::VIM::VirtualMachine).
30
+ select {|v| !v.config.nil? && v.config.template == true }
31
+
32
+ vms.each do |vm|
33
+ puts "#{ui.color("Template Name", :cyan)}: #{vm.name}"
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,275 @@
1
+ #
2
+ # Author:: Alexis Gruet (<alexis.gruet@kroknet.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+
6
+ require 'chef/knife/ovh_base'
7
+
8
+ # Clone an existing template into a new VM - bootstrap chef - and optionally give some recipes and/or roles
9
+ #
10
+ # usage:
11
+
12
+ # knife vsphere vm clone web06 00_UBUNTU-10.04 --domain intra.kroknet.com \
13
+ # --hostname web06 --ip 46.105.128.246 --gw 46.105.128.254 --dns 213.186.33.99 --netmask 255.255.255.224 \
14
+ # -d pcc-178-33-102-96_datacenter144 --ssh-user agruet --ssh-password test --distro ubuntu10.04-apt \
15
+ # -r 'recipe[kroknet-apt-repository_dev]'
16
+
17
+ class Chef
18
+ class Knife
19
+ class OvhPccVmClone < Knife
20
+
21
+ include Knife::OvhBase
22
+
23
+ deps do
24
+ require 'readline'
25
+ require 'netaddr'
26
+ require 'chef/json_compat'
27
+ require 'chef/knife/bootstrap'
28
+ Chef::Knife::Bootstrap.load_deps
29
+ end
30
+
31
+ banner "knife ovh pcc vm clone VMNAME TEMPLATE (options)"
32
+
33
+ attr_accessor :initial_sleep_delay
34
+
35
+ option :customization_ip,
36
+ :long => "--ip IP",
37
+ :description => "ip address for customization"
38
+
39
+ option :customization_netmask,
40
+ :long => "--netmask NETMASK",
41
+ :description => "netmask for customization"
42
+
43
+ option :customization_gw,
44
+ :long => "--gw GATEWAY",
45
+ :description => "gateway for customization"
46
+
47
+ option :customization_dns,
48
+ :long => "--dns DNS IP",
49
+ :description => "dns ip for customization"
50
+
51
+ option :customization_domain,
52
+ :long => "--domain CUST_DOMAIN",
53
+ :description => "domain name for customization"
54
+
55
+ option :customization_hostname,
56
+ :long => "--hostname HOSTNAME",
57
+ :description => "Unqualified hostname for customization"
58
+
59
+ option :customization_tz,
60
+ :long => "--tz CUST_TIMEZONE",
61
+ :description => "Timezone 'Area/Location' format"
62
+
63
+ option :distro,
64
+ :short => "-d DISTRO",
65
+ :long => "--distro DISTRO",
66
+ :description => "Bootstrap a distro using a template",
67
+ :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
68
+ :default => "ubuntu10.04-apt"
69
+
70
+ option :bootstrap_version,
71
+ :long => "--bootstrap-version VERSION",
72
+ :description => "The version of Chef to install",
73
+ :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
74
+
75
+ option :run_list,
76
+ :short => "-r RUN_LIST",
77
+ :long => "--run-list RUN_LIST",
78
+ :description => "Comma separated list of roles/recipes to apply",
79
+ :proc => lambda { |o| o.split(/[\s,]+/) },
80
+ :default => []
81
+
82
+ option :ssh_user,
83
+ :short => "-x USERNAME",
84
+ :long => "--ssh-user USERNAME",
85
+ :description => "The ssh username",
86
+ :default => "root"
87
+
88
+ option :ssh_password,
89
+ :short => "-P PASSWORD",
90
+ :long => "--ssh-password PASSWORD",
91
+ :description => "The ssh password"
92
+
93
+ option :power,
94
+ :long => "--start STARTVM",
95
+ :description => "Indicates whether to start the VM after a successful clone",
96
+ :default => true
97
+
98
+ def locate_config_value(key)
99
+ key = key.to_sym
100
+ Chef::Config[:knife][key] || config[key]
101
+ end
102
+
103
+ def tcp_test_ssh(hostname)
104
+ tcp_socket = TCPSocket.new(hostname, 22)
105
+ readable = IO.select([tcp_socket], nil, nil, 5)
106
+ if readable
107
+ Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
108
+ yield
109
+ true
110
+ else
111
+ false
112
+ end
113
+ rescue SocketError
114
+ sleep 2
115
+ false
116
+ rescue Errno::ETIMEDOUT
117
+ false
118
+ rescue Errno::EPERM
119
+ false
120
+ rescue Errno::ECONNREFUSED
121
+ sleep 2
122
+ false
123
+ # This happens on OVH quite often
124
+ rescue Errno::EHOSTUNREACH
125
+ sleep 2
126
+ false
127
+ ensure
128
+ tcp_socket && tcp_socket.close
129
+ end
130
+
131
+ # Run !
132
+ def run
133
+
134
+ $stdout.sync = true
135
+
136
+ vmname = @name_args[0]
137
+
138
+ if vmname.nil?
139
+ show_usage
140
+ fatal_exit("You must specify a virtual machine name")
141
+ end
142
+
143
+ template = @name_args[1]
144
+ if template.nil?
145
+ show_usage
146
+ fatal_exit("You must specify a template name")
147
+ end
148
+
149
+ vim = get_vim_connection
150
+
151
+ dcname = config[:vsphere_dc] || Chef::Config[:knife][:vsphere_dc]
152
+ dc = vim.serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
153
+
154
+ hosts = find_all_in_folders(dc.hostFolder, RbVmomi::VIM::ComputeResource)
155
+ rp = hosts.first.resourcePool
156
+
157
+ src_vm = find_in_folders(dc.vmFolder, RbVmomi::VIM::VirtualMachine, template) or
158
+ abort "VM/Template not found"
159
+
160
+ # kroknet - <alexis.gruet@kroknet.com>
161
+ # Fix to handle the vm creation with many parameters
162
+
163
+ fixed_name = RbVmomi::VIM.CustomizationFixedName
164
+ fixed_name.name = config[:customization_hostname]
165
+
166
+ # Global settings
167
+ vm_dns = RbVmomi::VIM.CustomizationGlobalIPSettings
168
+
169
+ my_dns = config[:customization_dns].split(',');
170
+ my_suffix = config[:customization_domain].split(',');
171
+
172
+ vm_dns.dnsServerList = my_dns
173
+ vm_dns.dnsSuffixList = my_suffix
174
+
175
+ # Who am i ?
176
+ identity_settings = RbVmomi::VIM.CustomizationLinuxPrep
177
+
178
+ identity_settings.hostName = fixed_name
179
+ identity_settings.domain = config[:customization_domain]
180
+ identity_settings.hwClockUTC = false
181
+ identity_settings.timeZone = 'Europe/Paris'
182
+
183
+ cidr_ip = NetAddr::CIDR.create(config[:customization_ip])
184
+
185
+ # IP
186
+ vm_ip = RbVmomi::VIM::CustomizationFixedIp(:ipAddress => cidr_ip.ip)
187
+
188
+ # IPV4 Settings eth0
189
+ vm_ip_settings = RbVmomi::VIM.CustomizationIPSettings
190
+
191
+ my_gw = config[:customization_gw].split(',');
192
+
193
+ vm_ip_settings.ip = vm_ip
194
+ vm_ip_settings.subnetMask = config[:customization_netmask]
195
+ vm_ip_settings.dnsServerList = my_dns
196
+ vm_ip_settings.gateway = my_gw
197
+ vm_ip_settings.dnsDomain = config[:customization_domain]
198
+
199
+ #adapter mapping
200
+ adapter_mapping = RbVmomi::VIM.CustomizationAdapterMapping
201
+ adapter_mapping.adapter = vm_ip_settings
202
+
203
+ customization_spec = RbVmomi::VIM.CustomizationSpec
204
+
205
+ multi_nic = [ adapter_mapping ]
206
+
207
+ customization_spec.globalIPSettings = vm_dns
208
+ customization_spec.identity = identity_settings
209
+ customization_spec.nicSettingMap = multi_nic
210
+
211
+ rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => rp)
212
+
213
+ clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:customization => customization_spec,
214
+ :location => rspec,
215
+ :powerOn => false,
216
+ :template => false)
217
+
218
+ task = src_vm.CloneVM_Task(:folder => src_vm.parent, :name => vmname, :spec => clone_spec)
219
+ puts "Cloning template #{template} to new VM #{vmname}"
220
+ task.wait_for_completion
221
+ puts "Finished creating virtual machine #{vmname}"
222
+
223
+ if config[:power]
224
+ vm = find_in_folders(dc.vmFolder, RbVmomi::VIM::VirtualMachine, vmname) or
225
+ fatal_exit("VM #{vmname} not found")
226
+ vm.PowerOnVM_Task.wait_for_completion
227
+ puts "Powered on virtual machine #{vmname}"
228
+
229
+ # TODO:
230
+ # Fix this crappy stuff - while loop is used
231
+ # to ensure the hostname is well done updated by the the tools
232
+ # should be nice to ask francois from ovh to figured out if one method exist to deal with this corner case
233
+ #
234
+ print "\n#{ui.color("Waiting for server", :magenta)}"
235
+
236
+ while vm.guest.hostName != vmname
237
+ print(".")
238
+ sleep 2
239
+ end
240
+
241
+ puts("\n")
242
+ print "\n#{ui.color("VM #{vmname} - Ready - Starting chef bootstrap", :magenta)}"
243
+ puts("\n")
244
+ print "\n#{ui.color("As to bootstrap chef we need a ssh conn - lets check for it", :magenta)}"
245
+
246
+ #or fatal_exit( "\n#{ui.color("No way to connect the remote server via SSH - IP : #{cidr_ip.ip} - If use used a private IP, ensure a vpn connection exist", :magenta)}" )
247
+
248
+ print "." until tcp_test_ssh(config[:customization_ip]) {
249
+ bootstrap = Chef::Knife::Bootstrap.new
250
+ bootstrap.name_args = [cidr_ip.ip]
251
+ bootstrap.config[:run_list] = config[:run_list]
252
+ bootstrap.config[:ssh_user] = config[:ssh_user]
253
+ bootstrap.config[:chef_node_name] = config[:chef_node_name]
254
+ bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
255
+ bootstrap.config[:distro] = locate_config_value(:distro)
256
+ bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
257
+ bootstrap.config[:environment] = config[:environment]
258
+
259
+ bootstrap.run
260
+
261
+ puts("\n")
262
+ puts("\n")
263
+ print "\n#{ui.color("server is up and bootstraped with a chef-client", :green)}"
264
+ puts("\n")
265
+
266
+ }
267
+ end
268
+
269
+ end # end run
270
+
271
+ end
272
+
273
+ end
274
+
275
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # Author:: Alexis Gruet (<alexis.gruet@kroknet.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+
6
+ require 'chef/knife/ovh_base'
7
+
8
+ # Delete a virtual machine from vCenter
9
+ class Chef
10
+ class Knife
11
+ class OvhPccVmDelete < Knife
12
+
13
+ include Knife::OvhBase
14
+
15
+ banner "knife ovh pcc vm delete VMNAME"
16
+
17
+ def run
18
+ $stdout.sync = true
19
+
20
+ vmname = @name_args[0]
21
+
22
+ if vmname.nil?
23
+ show_usage
24
+ fatal_exit("You must specify a virtual machine name")
25
+ end
26
+
27
+ vim = get_vim_connection
28
+
29
+ dcname = config[:vsphere_dc] || Chef::Config[:knife][:vsphere_dc]
30
+ dc = vim.serviceInstance.find_datacenter(dcname) or
31
+ fatal_exit("datacenter not found")
32
+
33
+ vm = find_in_folders(dc.vmFolder, RbVmomi::VIM::VirtualMachine,vmname) or fatal_exit("VM #{vmname} not found")
34
+
35
+ vm.PowerOffVM_Task.wait_for_completion unless vm.runtime.powerState == "poweredOff"
36
+ vm.Destroy_Task
37
+ puts "Deleted virtual machine #{vmname}"
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ #
2
+ # Author:: Alexis Gruet (<alexis.gruet@kroknet.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+
6
+ require 'chef/knife/ovh_base'
7
+
8
+ # Lists all known virtual machines in the configured datacenter
9
+ class Chef
10
+ class Knife
11
+ class OvhPccVmList < Knife
12
+
13
+ include Knife::OvhBase
14
+
15
+ banner "knife ovh pcc vm list"
16
+
17
+ option :folder,
18
+ :short => "-f SHOWFOLDER",
19
+ :long => "--folder",
20
+ :description => "The folder to list VMs in"
21
+
22
+ def run
23
+
24
+ $stdout.sync = true
25
+
26
+ vim = get_vim_connection
27
+
28
+ dcname = config[:vsphere_dc] || Chef::Config[:knife][:vsphere_dc]
29
+ dc = vim.serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
30
+
31
+ baseFolder = dc.vmFolder;
32
+
33
+ if config[:folder]
34
+ baseFolder = get_folders(dc.vmFolder).find { |f| f.name == config[:folder]} or
35
+ abort "no such folder #{config[:folder]}"
36
+ end
37
+
38
+ vms = find_all_in_folders(baseFolder, RbVmomi::VIM::VirtualMachine)
39
+ vms.each do |vm|
40
+ puts "#{ui.color("VM Name", :cyan)}: #{vm.name}"
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,6 @@
1
+ module Knife
2
+ module Ovh
3
+ VERSION = "0.0.2"
4
+ MAJOR, MINOR, TINY = VERSION.split('.')
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knife-ovh
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Alexis Gruet
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-01-06 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: netaddr
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 5
30
+ - 0
31
+ version: 1.5.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: chef
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 10
44
+ - 0
45
+ version: 0.10.0
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rbvmomi
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 1
57
+ - 5
58
+ - 0
59
+ version: 1.5.0
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ description: Ovh cloud interface vSphere Support for Chef's Knife Command
63
+ email: alexis.gruet@kroknet.com
64
+ executables: []
65
+
66
+ extensions: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ files:
71
+ - lib/chef/knife/ovh_base.rb
72
+ - lib/chef/knife/ovh_pcc_template_list.rb
73
+ - lib/chef/knife/ovh_pcc_vm_clone.rb
74
+ - lib/chef/knife/ovh_pcc_vm_delete.rb
75
+ - lib/chef/knife/ovh_pcc_vm_list.rb
76
+ - lib/knife-ovh/version.rb
77
+ has_rdoc: true
78
+ homepage:
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options: []
83
+
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Ovh cloud interface vSphere Support for Knife
107
+ test_files: []
108
+