knife-vcenter 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new(:style)
8
+
9
+ begin
10
+ require 'github_changelog_generator/task'
11
+
12
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
13
+ config.future_release = KnifeVcenter::VERSION
14
+ config.issues = true
15
+ end
16
+ rescue LoadError
17
+ puts 'github_changelog_generator is not available. gem install github_changelog_generator to generate changelogs'
18
+ end
19
+
20
+ task default: [ :spec, :style ]
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'knife-vcenter/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'knife-vcenter'
10
+ spec.version = KnifeVcenter::VERSION
11
+ spec.authors = ['Chef Partner Engineering']
12
+ spec.email = ['partnereng@chef.io']
13
+ spec.summary = 'Knife plugin to VMware vCenter.'
14
+ spec.description = spec.summary
15
+ spec.homepage = 'https://github.com/chef/knife-vcenter'
16
+ spec.license = 'Apache 2.0'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'chef', '~> 12'
24
+ spec.add_dependency 'knife-cloud', '~> 1.2'
25
+ spec.add_dependency 'rb-readline', '~> 0.5'
26
+ spec.add_dependency 'rbvmomi', '~> 1.11'
27
+ spec.add_dependency 'savon', '~> 2.11'
28
+ spec.add_dependency 'vsphere-automation-sdk', '~> 2.5'
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.7'
31
+ spec.add_development_dependency 'debase'
32
+ spec.add_development_dependency 'github_changelog_generator'
33
+ spec.add_development_dependency 'pry'
34
+ spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'rubocop', '~> 0.35'
36
+ spec.add_development_dependency 'ruby-debug-ide', '~> 0.6.0'
37
+
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
4
+ # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'logger'
21
+
22
+ module Base
23
+ attr_accessor :log
24
+
25
+ def self.log
26
+ @log ||= init_logger
27
+ end
28
+
29
+ def self.init_logger
30
+ log = Logger.new(STDOUT)
31
+ log.progname = 'Knife VCenter'
32
+ log.level = Logger::INFO
33
+ log
34
+ end
35
+ end
@@ -0,0 +1,256 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
4
+ # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife/cloud/exceptions'
21
+ require 'chef/knife/cloud/service'
22
+ require 'chef/knife/cloud/helpers'
23
+ require 'chef/knife/cloud/vcenter_service_helpers'
24
+ require 'net/http'
25
+ require 'uri'
26
+ require 'json'
27
+ require 'ostruct'
28
+ require 'lookup_service_helper'
29
+ require 'vapi'
30
+ require 'com/vmware/cis'
31
+ require 'com/vmware/vcenter'
32
+ require 'com/vmware/vcenter/vm'
33
+ require 'sso'
34
+ require 'base'
35
+ require 'set'
36
+ require 'support/clone_vm'
37
+
38
+ class Chef
39
+ class Knife
40
+ class Cloud
41
+ class VcenterService < Service
42
+ include VcenterServiceHelpers
43
+
44
+ attr_reader :vapi_config, :session_svc, :session_id
45
+ attr_reader :connection_options, :ipaddress
46
+
47
+ def initialize(options={})
48
+ super(options)
49
+
50
+ # Using the information supplied, configure the connection to vCentre
51
+ lookup_service_helper = LookupServiceHelper.new(options[:host])
52
+
53
+ vapi_urls = lookup_service_helper.find_vapi_urls()
54
+ vapi_url = vapi_urls.values[0]
55
+ Base.log.info(format('Vapi URL: %s', vapi_url)) if options[:vcenter_logs]
56
+
57
+ # Create the VAPI config object
58
+ ssl_options = {}
59
+ ssl_options[:verify] = if options[:verify_ssl]
60
+ :peer
61
+ else
62
+ Base.log.warn('SSL Verification is turned OFF') if options[:vcenter_logs]
63
+ :none
64
+ end
65
+ @vapi_config = VAPI::Bindings::VapiConfig.new(vapi_url, ssl_options)
66
+
67
+ # get the SSO url
68
+ sso_url = lookup_service_helper.find_sso_url()
69
+ sso = SSO::Connection.new(sso_url).login(options[:username], options[:password])
70
+ token = sso.request_bearer_token()
71
+ vapi_config.set_security_context(
72
+ VAPI::Security.create_saml_bearer_security_context(token.to_s)
73
+ )
74
+
75
+ # Login and get the session information
76
+ @session_svc = Com::Vmware::Cis::Session.new(vapi_config)
77
+ @session_id = session_svc.create()
78
+ vapi_config.set_security_context(
79
+ VAPI::Security.create_session_security_context(session_id)
80
+ )
81
+
82
+ # Set the class properties for the rbvmomi connections
83
+ @connection_options = {
84
+ user: options[:username],
85
+ password: options[:password],
86
+ insecure: options[:verify_ssl] ? false : true,
87
+ host: options[:host],
88
+ }
89
+ end
90
+
91
+ def create_server(options={})
92
+
93
+ # Create the vm object
94
+ vmobj = Com::Vmware::Vcenter::VM.new(vapi_config)
95
+
96
+ # Use the option to determine now a new machine is being created
97
+ case options[:type]
98
+ when "clone"
99
+
100
+ # Some of ht eoptions need to be the ID of the component in VMWAre
101
+ # Update these using the REST API so that they can be passed to the support library
102
+ options[:targethost] = get_host(options[:targethost])
103
+
104
+ # Configure the folder option as a has with the name an the id
105
+ options[:folder] = {
106
+ name: options[:folder],
107
+ id: get_folder(options[:folder])
108
+ } unless options[:folder].nil?
109
+
110
+ # Clone the machine using the support library
111
+ clone_obj = Support::CloneVm.new(connection_options, options)
112
+ @ipaddress = clone_obj.clone()
113
+
114
+ # return an object from the restapi
115
+ return get_server(options[:name])
116
+
117
+ when "create"
118
+
119
+ # Create the placement object
120
+ placementspec = Com::Vmware::Vcenter::VM::PlacementSpec.new()
121
+ placementspec.folder = get_folder(options[:folder])
122
+ placementspec.host = get_host(options[:targethost])
123
+ placementspec.datastore = get_datastore(options[:datastore])
124
+ placementspec.resource_pool = get_resourcepool(options[:resource_pool])
125
+
126
+ # Create the CreateSpec object
127
+ createspec = Com::Vmware::Vcenter::VM::CreateSpec.new()
128
+
129
+ createspec.name = options[:name]#
130
+ puts "seting the OS"
131
+ createspec.guest_OS = Com::Vmware::Vcenter::Vm::GuestOS::UBUNTU_64
132
+ puts "setting the placement"
133
+ createspec.placement = placementspec
134
+
135
+ # Create the new machine
136
+ begin
137
+ vm = vmobj.create(createspec)
138
+ rescue => e
139
+ puts e.message
140
+ end
141
+ end
142
+ end
143
+
144
+ def list_servers
145
+ # get a list of vms from the API
146
+ Com::Vmware::Vcenter::VM.new(vapi_config).list()
147
+ end
148
+
149
+ def list_hosts
150
+ # return a list of the hosts in the vcenter
151
+ Com::Vmware::Vcenter::Host.new(vapi_config).list()
152
+ end
153
+
154
+ def list_datacenters
155
+ Com::Vmware::Vcenter::Datacenter.new(vapi_config).list()
156
+ end
157
+
158
+ def list_clusters
159
+ Com::Vmware::Vcenter::Cluster.new(vapi_config).list()
160
+ end
161
+
162
+ def get_folder(name)
163
+ # Create a filter to ensure that only the named folder is returned
164
+ filter = Com::Vmware::Vcenter::Folder::FilterSpec.new({names: Set.new([name])})
165
+ # filter.names = name
166
+ folder_obj = Com::Vmware::Vcenter::Folder.new(vapi_config)
167
+ folder = folder_obj.list(filter)
168
+
169
+ folder[0].folder
170
+ end
171
+
172
+ def get_host(name)
173
+ filter = Com::Vmware::Vcenter::Host::FilterSpec.new({names: Set.new([name])})
174
+ host_obj = Com::Vmware::Vcenter::Host.new(vapi_config)
175
+ host = host_obj.list(filter)
176
+ host[0].host
177
+ end
178
+
179
+ def get_datastore(name)
180
+ filter = Com::Vmware::Vcenter::Datastore::FilterSpec.new({names: Set.new([name])})
181
+ datastore_obj = Com::Vmware::Vcenter::Datastore.new(vapi_config)
182
+ datastore = datastore_obj.list(filter)
183
+ datastore[0].datastore
184
+ end
185
+
186
+ def get_resourcepool(name)
187
+ filter = Com::Vmware::Vcenter::ResourcePool::FilterSpec.new({names: Set.new([name])})
188
+ resource_pool_obj = Com::Vmware::Vcenter::ResourcePool.new(vapi_config)
189
+ resource_pool = resource_pool_obj.list(filter)
190
+ resource_pool[0].resource_pool
191
+ end
192
+
193
+ def get_server(name)
194
+ filter = Com::Vmware::Vcenter::VM::FilterSpec.new({names: Set.new([name])})
195
+ vm_obj = Com::Vmware::Vcenter::VM.new(vapi_config)
196
+ vm_obj.list(filter)[0]
197
+ end
198
+
199
+ def delete_vm(name)
200
+ vm = get_server(name)
201
+ server_summary(vm)
202
+ ui.msg('')
203
+
204
+ ui.confirm('Do you really want to be delete this virtual machine')
205
+
206
+ vm_obj = Com::Vmware::Vcenter::VM.new(vapi_config)
207
+
208
+ # check the power state of the machine, if it is powered on turn it off
209
+ if vm.power_state.value == "POWERED_ON"
210
+ power = Com::Vmware::Vcenter::Vm::Power.new(vapi_config)
211
+ ui.msg('Shutting down machine')
212
+ power.stop(vm.vm)
213
+ end
214
+
215
+ vm_obj.delete(vm.vm)
216
+ end
217
+
218
+ def server_summary(server, _coloumns_with_inf=nil)
219
+ msg_pair('ID', server.vm)
220
+ msg_pair('Name', server.name)
221
+ msg_pair('Power State', server.power_state)
222
+ end
223
+
224
+ =begin
225
+ def bootstrap_common_params(bootstrap)
226
+ bootstrap.config[:run_list] = config[:run_list]
227
+ bootstrap.config[:environment] = get_config(:environment)
228
+ bootstrap.config[:first_boot_attributes] = get_config(:first_boot_attributes)
229
+ bootstrap.config[:chef_node_name] = get_config(:chef_node_name)
230
+ bootstrap.config[:node_ssl_verify_mode] = get_config(:node_ssl_verify_mode)
231
+ bootstrap
232
+ end
233
+
234
+ def bootstrap_for_node
235
+ Chef::Knife::Bootstrap.load_deps
236
+ bootstrap = Chef::Knife::Bootstrap.new
237
+ bootstrap.name_args = [config[:fqdn]]
238
+ bootstrap.config[:ssh_user] = get_config(:ssh_user)
239
+ bootstrap.config[:ssh_password] = get_config(:ssh_password)
240
+ bootstrap.config[:ssh_port] = get_config(:ssh_port)
241
+ bootstrap.config[:identity_file] = get_config(:identity_file)
242
+ bootstrap.config[:use_sudo] = true unless get_config(:ssh_user) == 'root'
243
+ bootstrap.config[:use_sudo_password] = true unless get_config(:ssh_user) == 'root'
244
+ bootstrap.config[:log_level] = get_config(:log_level)
245
+ bootstrap_common_params(bootstrap)
246
+ end
247
+ =end
248
+ private
249
+
250
+ def cleanup
251
+ session_svc.delete() unless session_id.nil?
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
4
+ # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife/cloud/helpers'
21
+
22
+ class Chef
23
+ class Knife
24
+ class Cloud
25
+ module VcenterServiceHelpers
26
+ include Chef::Knife::Cloud::Helpers
27
+
28
+ def create_service_instance
29
+ Chef::Knife::Cloud::VcenterService.new(username: locate_config_value(:vcenter_username),
30
+ password: locate_config_value(:vcenter_password),
31
+ host: locate_config_value(:vcenter_host),
32
+ verify_ssl: verify_ssl?)
33
+ end
34
+
35
+ def verify_ssl?
36
+ !locate_config_value(:vcenter_disable_ssl_verify)
37
+ end
38
+
39
+ def validate!
40
+ check_for_missing_config_values!(:vcenter_username, :vcenter_password, :vcenter_host)
41
+ end
42
+
43
+ # rubocop:disable Style/GuardClause
44
+ def check_for_missing_config_values!(*keys)
45
+ missing = keys.select { |x| locate_config_value(x).nil? }
46
+
47
+ unless missing.empty?
48
+ ui.error(format("The following required parameters are missing: %s", missing.join(', ')))
49
+ exit(1)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
4
+ # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ class Chef
21
+ class Knife
22
+ class Cloud
23
+ # rubocop:disable Style/AlignParameters
24
+ # runodop:disable Metrics/BlockLength
25
+ module VcenterServiceOptions
26
+ def self.included(includer)
27
+ includer.class_eval do
28
+ option :vcenter_username,
29
+ long: '--vcenter-username USERNAME',
30
+ description: 'Username to use to connect to the VCenter API'
31
+
32
+ option :vcenter_password,
33
+ long: '--vcenter-password PASSWORD',
34
+ description: 'Password associated with the specified user'
35
+
36
+ option :vcenter_host,
37
+ long: '--vcenter-host HOST',
38
+ description: 'Host to target for operations'
39
+
40
+ option :vcenter_disable_ssl_verify,
41
+ long: '--vcenter-disable-ssl-verify',
42
+ description: 'Skip any SSL verification for the API',
43
+ boolean: true,
44
+ default: false
45
+
46
+ option :vcenter_logs,
47
+ long: '--vcenter-logs',
48
+ description: 'Whether or not to display logs from VCenter SDK. Default: false',
49
+ boolean: true,
50
+ default: false
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end