Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add winrm support #12

Merged
merged 9 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 1 addition & 29 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,12 @@

## [Unreleased](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/HEAD)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test6...HEAD)
[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.2.0...HEAD)

**Merged pull requests:**

- added CHANGELOG update action [\#11](https://github.com/jmtx1020/kitchen-yansible-pusher/pull/11) ([jmtx1020](https://github.com/jmtx1020))

## [v0.1.4_test6](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test6) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test5...v0.1.4_test6)

## [v0.1.4_test5](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test5) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test4...v0.1.4_test5)

## [v0.1.4_test4](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test4) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test3...v0.1.4_test4)

## [v0.1.4_test3](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test3) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test2...v0.1.4_test3)

## [v0.1.4_test2](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test2) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test1...v0.1.4_test2)

## [v0.1.4_test1](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test1) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.4_test...v0.1.4_test1)

## [v0.1.4_test](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.1.4_test) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.2.0...v0.1.4_test)

## [v0.2.0](https://github.com/jmtx1020/kitchen-yansible-pusher/tree/v0.2.0) (2024-08-31)

[Full Changelog](https://github.com/jmtx1020/kitchen-yansible-pusher/compare/v0.1.3...v0.2.0)
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
kitchen-yansible-pusher (0.2.0)
kitchen-yansible-pusher (0.3.0)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -35,7 +35,7 @@ GEM
tty-box (~> 0.6)
tty-prompt (~> 0.20)
little-plugger (1.1.4)
logger (1.6.0)
logger (1.6.1)
logging (2.4.0)
little-plugger (~> 1.1)
multi_json (~> 1.14)
Expand Down
56 changes: 54 additions & 2 deletions lib/kitchen/provisioner/yansible_pusher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class YansiblePusher < Kitchen::Provisioner::Base # rubocop:disable Metrics/Clas
default_config :vault_password_file, nil
default_config :username, nil
default_config :private_key, nil
default_config :windows_config, nil

attr_reader :sandbox_path

Expand Down Expand Up @@ -62,6 +63,7 @@ def run_command
ensure
cleanup_sandbox
end
ensure_windows_exit_code if windows_instance?
end

private
Expand Down Expand Up @@ -89,13 +91,43 @@ def build_inventory
end

def build_host_config(state)
if windows_instance?
build_windows_config(state)
else
build_linux_config(state)
end
end

def build_linux_config(state)
{
'ansible_host' => state[:hostname],
'ansible_port' => state[:port],
'ansible_user' => config[:username] || state[:username]
}
end

def build_windows_config(state)
uri = URI(state[:endpoint])
defaults = default_windows_config(state, uri)
user_windows_config(defaults)
end

def user_windows_config(defaults)
user_config = (config[:winrm_config] || {}).transform_keys { |key| "ansible_#{key}" }
defaults.merge(user_config.compact)
end

def default_windows_config(state, uri)
{ 'ansible_host' => uri.host,
'ansible_port' => state[:port] || uri.port,
'ansible_user' => state[:user],
'ansible_password' => state[:password],
'ansible_connection' => 'winrm',
'ansible_winrm_server_cert_validation' => 'ignore',
'ansible_winrm_transport' => 'ssl',
'ansible_winrm_scheme' => uri.scheme }
end

def write_inventory_file(inventory)
inventory_file = File.join(sandbox_path, 'inventory.yml')
File.write(inventory_file, inventory.to_yaml)
Expand Down Expand Up @@ -134,7 +166,7 @@ def ansible_env_vars(cmd)
end

def ansible_extra_flags(cmd)
cmd << "#{config[:extra_flags].join(" ")}" unless config[:extra_flags].empty?
cmd << config[:extra_flags].join(' ') unless config[:extra_flags].empty?
cmd
end

Expand All @@ -153,7 +185,7 @@ def ansible_use_private_key(cmd)
cmd << "--private-key #{config[:private_key]}"
else
state = instance.transport.instance_variable_get(:@connection_options)
cmd << "--private-key #{state[:keys][0]}"
cmd << "--private-key #{state[:keys][0]}" if state.key?(:keys)
end
cmd
end
Expand All @@ -165,6 +197,7 @@ def ansible_use_vault_password_file(cmd)

def ansible_verbosity(cmd)
cmd << "-#{'v' * config[:verbosity]}" if config[:verbosity] >= 1
cmd
end

def create_sandbox
Expand All @@ -186,6 +219,25 @@ def cleanup_sandbox
error("Failed to clean up sandbox: #{e.message}")
raise
end

def windows_instance?
instance.transport.instance_variable_get(:@connection_options).key?(:endpoint)
end

# Ensures proper exit code handling for Windows instances in Test Kitchen.
#
# @return [String] A PowerShell command string to be executed on the remote Windows system.
#
# This method is only called for Windows instances. It returns a PowerShell command that:
# 1. Outputs the status of the last command ($?)
# 2. Exits with 0 if the last command succeeded, or 1 if it failed
#
# This approach addresses a specific issue with Test Kitchen's WinRM transport,
# where it expects a command string to execute rather than a boolean result.
# It ensures that the correct exit code is returned to Test Kitchen.
def ensure_windows_exit_code
'$?; if($?) { exit 0 } else { exit 1 }'
end
end
end
end
2 changes: 1 addition & 1 deletion lib/kitchen/yansible/pusher/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Kitchen
module Yansible
module Pusher
VERSION = "0.2.0"
VERSION = "0.3.0"
end
end
end
55 changes: 55 additions & 0 deletions spec/integration/yansible_pusher_integration_winrm_vagrant_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'spec_helper'
require 'kitchen/driver/docker'
require 'kitchen/provisioner/yansible_pusher'
require 'kitchen/verifier/busser'
require 'kitchen/loader/yaml'
require 'kitchen/config'
require 'fileutils'

describe 'YansiblePusher Windows Integration(WinRM)', :winrm do
before(:all) do
Kitchen.logger = Kitchen.default_file_logger
end

let(:loader) do
Kitchen::Loader::YAML.new(
project_config: File.expand_path('../../test/integration/ansible/kitchen_win.yml', __dir__)
)
end

let(:config) { Kitchen::Config.new(loader: loader) }
let(:instance) { config.instances.first }
let(:kitchen_root) { File.expand_path('../..', __dir__) }
let(:log_file) { File.join(kitchen_root, '.kitchen', 'logs', "#{instance.name}.log") }

before(:each) do
instance.create
end

after(:each) do
instance.destroy
rescue => e
puts "Error during instance destruction: #{e.message}"
ensure
FileUtils.rm_rf(instance.instance_variable_get(:@data_path)) if instance.instance_variable_get(:@data_path)
end

it 'verifies ansible playbook execution on windows via WinRM' do
# Ensure the log directory exists
FileUtils.mkdir_p(File.dirname(log_file))

# Clear the log file before running converge
File.write(log_file, '')

# Run the converge action
instance.converge
# expect { instance.test }.not_to raise_error

# Read the log file
log_content = File.read(log_file)

# Perform checks on the log content
expect(log_content).to include('Running Ansible Playbook')
expect(log_content).to include('Ansible Playbook Complete!')
end
end
5 changes: 2 additions & 3 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

require 'kitchen/provisioner/yansible_pusher'

# Load all integration test files
Dir[File.expand_path("../integration/**/*_spec.rb", __FILE__)].each { |f| require f }

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
Expand All @@ -13,6 +10,8 @@
config.disable_monkey_patching!
config.expose_dsl_globally = true

config.filter_run_excluding winrm: true # use this to test on non windows systems


config.expect_with :rspec do |c|
c.syntax = :expect
Expand Down
2 changes: 0 additions & 2 deletions test/integration/ansible/kitchen.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
driver:
name: docker
customize:
memory: 1024

platforms:
- name: ubuntu-22.04
Expand Down
35 changes: 35 additions & 0 deletions test/integration/ansible/kitchen_win.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
driver:
name: vagrant
customize:
memory: 1024
platforms:
- name: windows-2022
driver:
box: gusztavvargadr/windows-server-2022-standard
gui: true
communicator: winrm
network:
- ["forwarded_port", {guest: 5985, host: 55985}]
transport:
name: winrm

provisioner:
name: yansible_pusher
playbook: test/integration/ansible/playbooks/playbook_win.yaml
config: test/integration/ansible/playbooks/ansible.cfg
verbosity: 1
vault_password_file: test/integration/ansible/password.secret
extra_flags:
- --flush-cache
- --timeout 60
env_vars:
MARIO: "MUSHROOM_KINGDOM"
LINK: "HYRULE"
tags:
- win_tag1
skip_tags:
- win_skip_tag1

suites:
- name: default
12 changes: 12 additions & 0 deletions test/integration/ansible/playbooks/playbook_win.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
- name: Playbook1 to run the ansible_test locally
hosts: all
gather_facts: true
roles:
- role: ../roles/ansible_test

- name: Playbook2 to run the ansible_test locally
hosts: all
gather_facts: true
roles:
- role: ../roles/ansible_test
10 changes: 10 additions & 0 deletions test/integration/ansible/roles/ansible_test/requirements.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
collections:
- name: ansible.windows
version: 2.5.0

- name: community.windows
version: 2.3.0

- name: chocolatey.chocolatey
version: 1.5.1
Loading
Loading