train-vmware 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 238630d02bbca3ff3ba2bf7c27577bcb291222c3dbed50918601ac2100293989
4
+ data.tar.gz: 900a9ccf490ad20969bd1bda9e8cab0e309d44535df143cd665b8061bbd30448
5
+ SHA512:
6
+ metadata.gz: '09d46aaad75d424f1f3042627dc08cf4ba3b9205a97d72d2fedbe68663cccc7f7e75fa37836828059e6b6d5c49127c9944d235e56b7be4783f66d18198feb354'
7
+ data.tar.gz: 31f060e25871a77e487731566e490a2899f4c7f892395adbd7b582ae7d96ab3eb171e2a085c7da4ec9e1c4633573ca26eaf8edc4f9e2b7fba8d69a84d5856a18
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "https://rubygems.org"
2
+
3
+ # This is Gemfile, which is used by bundler
4
+ # to ensure a coherent set of gems is installed.
5
+ # This file lists dependencies needed when outside
6
+ # of a gem (the gemspec lists deps for gem deployment)
7
+
8
+ # Bundler should refer to the gemspec for any dependencies.
9
+ gemspec
10
+
11
+ # Remaining group is only used for development.
12
+ group :development do
13
+ gem "bundler"
14
+ gem "byebug"
15
+ gem "inspec", ">= 2.2.112" # We need InSpec for the test harness while developing.
16
+ gem "minitest"
17
+ gem "rake"
18
+ gem "rubocop", "= 0.49.1" # Need to keep in sync with main InSpec project, so config files will work
19
+ end
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # train-vmware
2
+
3
+ InSpec Train Plugin for vSphere
4
+
5
+
6
+ gem build .\train-vmware.gemspec
7
+
8
+ gem push .\train-vmware-0.1.1.gem
@@ -0,0 +1,175 @@
1
+ # This allow us to inherit from Train::Plugins::Transport::BaseConnection
2
+ require "train"
3
+ require "open3"
4
+ require "ostruct" unless defined?(OpenStruct)
5
+ require "json" unless defined?(JSON)
6
+ require "mkmf"
7
+
8
+ module TrainPlugins
9
+ module VMware
10
+ # You must inherit from BaseConnection.
11
+ class Connection < Train::Plugins::Transport::BaseConnection
12
+ POWERSHELL_PROMPT_REGEX = /PS\s.*> $/.freeze
13
+
14
+ def initialize(options)
15
+ super(options)
16
+
17
+ options[:viserver] = options[:viserver] || options[:host]
18
+ options[:username] = options[:username] || options[:user]
19
+
20
+ @username = options[:username]
21
+ @viserver = options[:viserver]
22
+ @session = nil
23
+ @stdout_buffer = ""
24
+ @stderr_buffer = ""
25
+
26
+ @powershell_binary = detect_powershell_binary
27
+
28
+ if @powershell_binary == :powershell
29
+ require "train/transports/local"
30
+ @powershell = Train::Transports::Local::Connection.new(options)
31
+ end
32
+
33
+ if options[:insecure] == true
34
+ run_command_via_connection("Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Scope Session -Confirm:$False")
35
+ end
36
+
37
+ @platform_details = {
38
+ release: "vmware-powercli-#{powercli_version}",
39
+ }
40
+
41
+ connect
42
+ end
43
+
44
+ def connect
45
+ login_command = "Connect-VIServer #{options[:viserver]} -User #{options[:username]} -Password #{options[:password]} | Out-Null"
46
+ result = run_command_via_connection(login_command)
47
+
48
+ if result.exit_status != 0
49
+ message = "Unable to connect to VIServer at #{options[:viserver]}. "
50
+ case result.stderr
51
+ when /Invalid server certificate/
52
+ message += "Certification verification failed. Please use `--insecure` or set `Set-PowerCLIConfiguration -InvalidCertificateAction Ignore` in PowerShell"
53
+ when /incorrect user name or password/
54
+ message += "Incorrect username or password"
55
+ else
56
+ message += result.stderr.gsub(/-Password .*\s/, "-Password REDACTED")
57
+ end
58
+
59
+ raise message
60
+ end
61
+ end
62
+
63
+ def platform
64
+ force_platform!("vmware", @platform_details)
65
+ end
66
+
67
+ def run_command_via_connection(cmd, &_data_handler)
68
+ if @powershell_binary == :pwsh
69
+ result = parse_pwsh_output(cmd)
70
+
71
+ # Attach exit status to result
72
+ exit_status = parse_pwsh_output("echo $?").stdout.chomp
73
+ result.exit_status = exit_status == "True" ? 0 : 1
74
+
75
+ result
76
+ else
77
+ @powershell.run_command(cmd)
78
+ end
79
+ end
80
+
81
+ def unique_identifier
82
+ uuid_command = "(Get-VMHost | Get-View).hardware.systeminfo.uuid"
83
+ run_command_via_connection(uuid_command).stdout.chomp
84
+ end
85
+
86
+ def uri
87
+ "vmware://#{@username}@#{@viserver}"
88
+ end
89
+
90
+ private
91
+
92
+ def detect_powershell_binary
93
+ if find_executable0("powershell")
94
+ :powershell
95
+ elsif find_executable0("pwsh")
96
+ :pwsh
97
+ else
98
+ raise "Cannot find PowerShell binary, is `pwsh` installed?"
99
+ end
100
+ end
101
+
102
+ # Read from stdout pipe until prompt is received
103
+ def flush_stdout(pipe)
104
+ @stdout_buffer += pipe.read_nonblock(1) while @stdout_buffer !~ POWERSHELL_PROMPT_REGEX
105
+ @stdout_buffer
106
+ rescue IO::EAGAINWaitReadable
107
+ # We cannot know when the stdout pipe is finished so we keep reading
108
+ retry
109
+ ensure
110
+ @stdout_buffer = ""
111
+ end
112
+
113
+ # This must be called after `flush_stdout` to ensure buffer is full
114
+ def flush_stderr(pipe)
115
+ loop do
116
+ @stderr_buffer += pipe.read_nonblock(1)
117
+ end
118
+ rescue IO::EAGAINWaitReadable
119
+ # If `flush_stderr` is ran after reading stdout we know that all of
120
+ # stderr is in the pipe. Thus, we can return the buffer once the pipe
121
+ # is unreadable.
122
+ @stderr_buffer
123
+ ensure
124
+ @stderr_buffer = ""
125
+ end
126
+
127
+ def parse_pwsh_output(cmd)
128
+ session.stdin.puts(cmd)
129
+
130
+ stdout = flush_stdout(session.stdout)
131
+
132
+ # Remove stdin from stdout (including trailing newline)
133
+ stdout.slice!(0, cmd.length + 1)
134
+
135
+ # Remove prompt from stdout
136
+ stdout.gsub!(POWERSHELL_PROMPT_REGEX, "")
137
+
138
+ # Grab stderr
139
+ stderr = flush_stderr(session.stderr)
140
+
141
+ CommandResult.new(
142
+ stdout,
143
+ stderr,
144
+ nil # exit_status is attached in `run_command_via_connection`
145
+ )
146
+ end
147
+
148
+ def powercli_version
149
+ version_command = "[string](Get-Module -Name VMware.PowerCLI -ListAvailable | Select -ExpandProperty Version)"
150
+ result = run_command_via_connection(version_command)
151
+ if result.stdout.empty? || result.exit_status != 0
152
+ raise "Unable to determine PowerCLI Module version, is it installed?"
153
+ end
154
+
155
+ result.stdout.chomp
156
+ end
157
+
158
+ def session
159
+ return @session unless @session.nil?
160
+
161
+ stdin, stdout, stderr = Open3.popen3("pwsh")
162
+
163
+ # Remove leading prompt and intro text
164
+ flush_stdout(stdout)
165
+
166
+ @session = OpenStruct.new
167
+ @session.stdin = stdin
168
+ @session.stdout = stdout
169
+ @session.stderr = stderr
170
+
171
+ @session
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,21 @@
1
+ require "train-vmware/connection"
2
+
3
+ # Train Plugins v1 are usually declared under the TrainPlugins namespace.
4
+ # Each plugin has three components: Transport, Connection, and (optionally) Platform.
5
+ # We'll only define the Transport here, but we'll refer to the others.
6
+
7
+ module TrainPlugins
8
+ module VMware
9
+ class VMware < Train.plugin(1)
10
+ name "vmware"
11
+ option :viserver, default: proc { ENV["VISERVER"] }
12
+ option :username, default: proc { ENV["VISERVER_USERNAME"] }
13
+ option :password, default: proc { ENV["VISERVER_PASSWORD"] }
14
+ option :insecure, default: false
15
+
16
+ def connection(_ = nil)
17
+ @connection ||= Connection.new(@options)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # This file exists simply to record the version number of the plugin.
2
+ # It is kept in a separate file, so that your gemspec can load it and
3
+ # learn the current version without loading the whole plugin. Also,
4
+ # many CI servers can update this file when "version bumping".
5
+
6
+ module TrainPlugins
7
+ module VMware
8
+ VERSION = "0.1.4".freeze
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ # This file is known as the "entry point."
2
+ # This is the file Train will try to load if it
3
+ # thinks your plugin is needed.
4
+
5
+ # The *only* thing this file should do is setup the
6
+ # load path, then load plugin files.
7
+
8
+ # Next two lines simply add the path of the gem to the load path.
9
+ # This is not needed when being loaded as a gem; but when doing
10
+ # plugin development, you may need it. Either way, it's harmless.
11
+ libdir = File.dirname(__FILE__)
12
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
13
+
14
+ # It's traditional to keep your gem version in a separate file, so CI can find it easier.
15
+ require_relative "train-vmware/version"
16
+
17
+ # A train plugin has three components: Transport, Connection, and (optionally) Platform.
18
+ # Transport acts as the glue.
19
+ require_relative "train-vmware/transport"
20
+ require_relative "train-vmware/connection"
@@ -0,0 +1,45 @@
1
+ # As plugins are usually packaged and distributed as a RubyGem,
2
+ # we have to provide a .gemspec file, which controls the gembuild
3
+ # and publish process. This is a fairly generic gemspec.
4
+
5
+ # It is traditional in a gemspec to dynamically load the current version
6
+ # from a file in the source tree. The next three lines make that happen.
7
+ lib = File.expand_path("lib", __dir__)
8
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
9
+ require "train-vmware/version"
10
+
11
+ Gem::Specification.new do |spec|
12
+ # Importantly, all Train plugins must be prefixed with `train-`
13
+ spec.name = "train-vmware"
14
+
15
+ # It is polite to namespace your plugin under TrainPlugins::YourPluginInCamelCase
16
+ spec.version = TrainPlugins::VMware::VERSION
17
+ spec.authors = ["VMware"]
18
+ spec.email = ["none@none.com"]
19
+ spec.summary = "Train Plugin for VMware PowerCLI"
20
+ spec.description = "Plugin version of the native VMware Transport in InSpec Train"
21
+ spec.homepage = ""
22
+ spec.license = "Apache-2.0"
23
+
24
+ # Though complicated-looking, this is pretty standard for a gemspec.
25
+ # It just filters what will actually be packaged in the gem (leaving
26
+ # out tests, etc)
27
+ spec.files = %w{
28
+ README.md train-vmware.gemspec Gemfile
29
+ } + Dir.glob(
30
+ "lib/**/*", File::FNM_DOTMATCH
31
+ ).reject { |f| File.directory?(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # If you rely on any other gems, list them here with any constraints.
35
+ # This is how `inspec plugin install` is able to manage your dependencies.
36
+ # For example, perhaps you are writing a thing that talks to AWS, and you
37
+ # want to ensure you have `aws-sdk` in a certain version.
38
+
39
+ # If you only need certain gems during development or testing, list
40
+ # them in Gemfile, not here.
41
+ # Do not list inspec as a dependency of the train plugin.
42
+
43
+ # All plugins should mention train, > 1.4
44
+ spec.add_dependency "train", "~> 3.8"
45
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: train-vmware
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - VMware
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: train
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.8'
27
+ description: Plugin version of the native VMware Transport in InSpec Train
28
+ email:
29
+ - none@none.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - Gemfile
35
+ - README.md
36
+ - lib/train-vmware.rb
37
+ - lib/train-vmware/connection.rb
38
+ - lib/train-vmware/transport.rb
39
+ - lib/train-vmware/version.rb
40
+ - train-vmware.gemspec
41
+ homepage: ''
42
+ licenses:
43
+ - Apache-2.0
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.2.32
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Train Plugin for VMware PowerCLI
64
+ test_files: []