summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Chamberland <chamberland.marc@gmail.com>2020-02-24 14:18:07 -0500
committerMarc Chamberland <chamberland.marc@gmail.com>2020-02-24 14:18:07 -0500
commit8a0ef12a66480e520c0ea7ea97e30ef13f0bef49 (patch)
treed898cb253cc9e31bdd1aa95d6f2931c308a7d9fa
parent922e8842c7a1bb3ecd5e6b268623a7d6badec8f4 (diff)
downloadchef-8a0ef12a66480e520c0ea7ea97e30ef13f0bef49.tar.gz
remove static wrapper script
Signed-off-by: Marc Chamberland <chamberland.marc@gmail.com>
-rw-r--r--distro/powershell/chef/chef.psm1459
1 files changed, 0 insertions, 459 deletions
diff --git a/distro/powershell/chef/chef.psm1 b/distro/powershell/chef/chef.psm1
deleted file mode 100644
index 05fee05e5e..0000000000
--- a/distro/powershell/chef/chef.psm1
+++ /dev/null
@@ -1,459 +0,0 @@
-
-function Load-Win32Bindings {
- Add-Type -TypeDefinition @"
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace Chef
-{
-
-[StructLayout(LayoutKind.Sequential)]
-public struct PROCESS_INFORMATION
-{
- public IntPtr hProcess;
- public IntPtr hThread;
- public uint dwProcessId;
- public uint dwThreadId;
-}
-
-[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
-public struct STARTUPINFO
-{
- public uint cb;
- public string lpReserved;
- public string lpDesktop;
- public string lpTitle;
- public uint dwX;
- public uint dwY;
- public uint dwXSize;
- public uint dwYSize;
- public uint dwXCountChars;
- public uint dwYCountChars;
- public uint dwFillAttribute;
- public STARTF dwFlags;
- public ShowWindow wShowWindow;
- public short cbReserved2;
- public IntPtr lpReserved2;
- public IntPtr hStdInput;
- public IntPtr hStdOutput;
- public IntPtr hStdError;
-}
-
-[StructLayout(LayoutKind.Sequential)]
-public struct SECURITY_ATTRIBUTES
-{
- public int length;
- public IntPtr lpSecurityDescriptor;
- public bool bInheritHandle;
-}
-
-[Flags]
-public enum CreationFlags : int
-{
- NONE = 0,
- DEBUG_PROCESS = 0x00000001,
- DEBUG_ONLY_THIS_PROCESS = 0x00000002,
- CREATE_SUSPENDED = 0x00000004,
- DETACHED_PROCESS = 0x00000008,
- CREATE_NEW_CONSOLE = 0x00000010,
- CREATE_NEW_PROCESS_GROUP = 0x00000200,
- CREATE_UNICODE_ENVIRONMENT = 0x00000400,
- CREATE_SEPARATE_WOW_VDM = 0x00000800,
- CREATE_SHARED_WOW_VDM = 0x00001000,
- CREATE_PROTECTED_PROCESS = 0x00040000,
- EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
- CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
- CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
- CREATE_DEFAULT_ERROR_MODE = 0x04000000,
- CREATE_NO_WINDOW = 0x08000000,
-}
-
-[Flags]
-public enum STARTF : uint
-{
- STARTF_USESHOWWINDOW = 0x00000001,
- STARTF_USESIZE = 0x00000002,
- STARTF_USEPOSITION = 0x00000004,
- STARTF_USECOUNTCHARS = 0x00000008,
- STARTF_USEFILLATTRIBUTE = 0x00000010,
- STARTF_RUNFULLSCREEN = 0x00000020, // ignored for non-x86 platforms
- STARTF_FORCEONFEEDBACK = 0x00000040,
- STARTF_FORCEOFFFEEDBACK = 0x00000080,
- STARTF_USESTDHANDLES = 0x00000100,
-}
-
-public enum ShowWindow : short
-{
- SW_HIDE = 0,
- SW_SHOWNORMAL = 1,
- SW_NORMAL = 1,
- SW_SHOWMINIMIZED = 2,
- SW_SHOWMAXIMIZED = 3,
- SW_MAXIMIZE = 3,
- SW_SHOWNOACTIVATE = 4,
- SW_SHOW = 5,
- SW_MINIMIZE = 6,
- SW_SHOWMINNOACTIVE = 7,
- SW_SHOWNA = 8,
- SW_RESTORE = 9,
- SW_SHOWDEFAULT = 10,
- SW_FORCEMINIMIZE = 11,
- SW_MAX = 11
-}
-
-public enum StandardHandle : int
-{
- Input = -10,
- Output = -11,
- Error = -12
-}
-
-public enum HandleFlags : int
-{
- HANDLE_FLAG_INHERIT = 0x00000001,
- HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002
-}
-
-public static class Kernel32
-{
- [DllImport("kernel32.dll", SetLastError=true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool CreateProcess(
- string lpApplicationName,
- string lpCommandLine,
- ref SECURITY_ATTRIBUTES lpProcessAttributes,
- ref SECURITY_ATTRIBUTES lpThreadAttributes,
- [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
- CreationFlags dwCreationFlags,
- IntPtr lpEnvironment,
- string lpCurrentDirectory,
- ref STARTUPINFO lpStartupInfo,
- out PROCESS_INFORMATION lpProcessInformation);
-
- [DllImport("kernel32.dll", SetLastError=true)]
- public static extern IntPtr GetStdHandle(
- StandardHandle nStdHandle);
-
- [DllImport("kernel32.dll")]
- public static extern bool SetHandleInformation(
- IntPtr hObject,
- int dwMask,
- uint dwFlags);
-
- [DllImport("kernel32", SetLastError=true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool CloseHandle(
- IntPtr hObject);
-
- [DllImport("kernel32", SetLastError=true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool GetExitCodeProcess(
- IntPtr hProcess,
- out int lpExitCode);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern bool CreatePipe(
- out IntPtr phReadPipe,
- out IntPtr phWritePipe,
- IntPtr lpPipeAttributes,
- uint nSize);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern bool ReadFile(
- IntPtr hFile,
- [Out] byte[] lpBuffer,
- uint nNumberOfBytesToRead,
- ref int lpNumberOfBytesRead,
- IntPtr lpOverlapped);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern bool PeekNamedPipe(
- IntPtr handle,
- byte[] buffer,
- uint nBufferSize,
- ref uint bytesRead,
- ref uint bytesAvail,
- ref uint BytesLeftThisMessage);
-
- public const int STILL_ACTIVE = 259;
-}
-}
-"@
-}
-
-function Run-ExecutableAndWait($AppPath, $ArgumentString) {
- # Use the Win32 API to create a new process and wait for it to terminate.
- $null = Load-Win32Bindings
-
- $si = New-Object Chef.STARTUPINFO
- $pi = New-Object Chef.PROCESS_INFORMATION
-
- $pSec = New-Object Chef.SECURITY_ATTRIBUTES
- $pSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($pSec)
- $pSec.bInheritHandle = $true
- $tSec = New-Object Chef.SECURITY_ATTRIBUTES
- $tSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($tSec)
- $tSec.bInheritHandle = $true
-
- # Create pipe for process stdout
- $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($si))
- [System.Runtime.InteropServices.Marshal]::StructureToPtr($pSec, $ptr, $true)
- $hReadOut = [IntPtr]::Zero
- $hWriteOut = [IntPtr]::Zero
- $success = [Chef.Kernel32]::CreatePipe([ref] $hReadOut, [ref] $hWriteOut, $ptr, 0)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to create output pipe. Error code $reason."
- }
- $success = [Chef.Kernel32]::SetHandleInformation($hReadOut, [Chef.HandleFlags]::HANDLE_FLAG_INHERIT, 0)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to set output pipe handle information. Error code $reason."
- }
-
- $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
- $si.wShowWindow = [Chef.ShowWindow]::SW_SHOW
- $si.dwFlags = [Chef.STARTF]::STARTF_USESTDHANDLES
- $si.hStdOutput = $hWriteOut
- $si.hStdError = $hWriteOut
- $si.hStdInput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Input)
-
- $success = [Chef.Kernel32]::CreateProcess(
- $AppPath,
- $ArgumentString,
- [ref] $pSec,
- [ref] $tSec,
- $true,
- [Chef.CreationFlags]::NONE,
- [IntPtr]::Zero,
- $pwd,
- [ref] $si,
- [ref] $pi
- )
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to create process [$ArgumentString]. Error code $reason."
- }
-
- $buffer = New-Object byte[] 1024
-
- # Initialize reference variables
- $bytesRead = 0
- $bytesAvailable = 0
- $bytesLeftThisMsg = 0
- $global:LASTEXITCODE = [Chef.Kernel32]::STILL_ACTIVE
-
- $isActive = $true
- while ($isActive) {
- $success = [Chef.Kernel32]::GetExitCodeProcess($pi.hProcess, [ref] $global:LASTEXITCODE)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Process exit code unavailable. Error code $reason."
- }
-
- $success = [Chef.Kernel32]::PeekNamedPipe(
- $hReadOut,
- $null,
- $buffer.Length,
- [ref] $bytesRead,
- [ref] $bytesAvailable,
- [ref] $bytesLeftThisMsg
- )
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Output pipe unavailable for peeking. Error code $reason."
- }
-
- if ($bytesRead -gt 0) {
- while ([Chef.Kernel32]::ReadFile($hReadOut, $buffer, $buffer.Length, [ref] $bytesRead, 0)) {
- $output = [Text.Encoding]::UTF8.GetString($buffer, 0, $bytesRead)
- if ($output) {
- $output
- }
- if ($bytesRead -lt $buffer.Length) {
- # Partial buffer indicating the end of stream, break out of ReadFile loop
- # ReadFile will block until:
- # The number of bytes requested is read.
- # A write operation completes on the write end of the pipe.
- # An asynchronous handle is being used and the read is occurring asynchronously.
- # An error occurs.
- break
- }
- }
- } else {
- # For some reason, you can't read from the read-end of the read-pipe before the write end has started
- # to write. Otherwise the process just blocks forever and never returns from the read. So we peek
- # at the pipe until there is something. But don't peek too eagerly. This is stupid stupid stupid.
- # There must be a way to do this without having to peek at a pipe first but I have not found it.
- #
- # Note to the future intrepid soul who wants to fix this:
- # 0) This is related to unreasonable CPU usage by the wrapper PS script on a 1 VCPU VM (either Hyper-V
- # or VirtualBox) running a consumer Windows SKU (Windows 10 for example...). Test it there.
- # 1) Maybe this entire script is unnecessary and the bugs mentioned below have been fixed or don't need
- # to be supported.
- # 2) The server and consumer windows schedulers have different defaults. I had a hard time reproducing
- # any issue on a win 2008 on win 2012 server default setup. See the "foreground application scheduler
- # priority" setting to see if it's relevant.
- # 3) This entire endeavor is silly anyway - why are we reimplementing process forking all over? Maybe try
- # to get the folks above to accept patches instead of extending this crazy script.
- Start-Sleep -s 1
- # Start-Sleep -m 100
- }
-
- if ($global:LASTEXITCODE -ne [Chef.Kernel32]::STILL_ACTIVE) {
- $isActive = $false
- }
- }
-
- # Cleanup handles
- $success = [Chef.Kernel32]::CloseHandle($pi.hProcess)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to release process handle. Error code $reason."
- }
- $success = [Chef.Kernel32]::CloseHandle($pi.hThread)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to release thread handle. Error code $reason."
- }
- $success = [Chef.Kernel32]::CloseHandle($hWriteOut)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to release output write handle. Error code $reason."
- }
- $success = [Chef.Kernel32]::CloseHandle($hReadOut)
- if (-Not $success) {
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- throw "Unable to release output read handle. Error code $reason."
- }
- [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
-}
-
-function Get-ScriptDirectory {
- if (!$PSScriptRoot) {
- $Invocation = (Get-Variable MyInvocation -Scope 1).Value
- $PSScriptRoot = Split-Path $Invocation.MyCommand.Path
- }
- $PSScriptRoot
-}
-
-function Run-RubyCommand($command, $argList) {
- # This method exists to take the given list of arguments and get it past ruby's command-line
- # interpreter unscathed and untampered. See https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L1582
- # for a list of transformations that ruby attempts to perform with your command-line arguments
- # before passing it onto a script. The most important task is to defeat the globbing
- # and wild-card expansion that ruby performs. Note that ruby does not use MSVCRT's argc/argv
- # and deliberately reparses the raw command-line instead.
- #
- # To stop ruby from interpreting command-line arguments as globs, they need to be enclosed in '
- # Ruby doesn't allow any escape characters inside '. This unfortunately prevents us from sending
- # any strings which themselves contain '. Ruby does allow multi-fragment arguments though.
- # "foo bar"'baz qux'123"foo" is interpreted as 1 argument because there are no un-escaped
- # whitespace there. The argument would be interpreted as the string "foo barbaz qux123foo".
- # This lets us escape ' characters by exiting the ' quoted string, injecting a "'" fragment and
- # then resuming the ' quoted string again.
- #
- # In the process of defeating ruby, one must also defeat the helpfulness of powershell.
- # When arguments come into this method, the standard PS rules for interpreting cmdlet arguments
- # apply. When using & (call operator) and providing an array of arguments, powershell (verified
- # on PS 4.0 on Windows Server 2012R2) will not evaluate them but (contrary to documentation),
- # it will still marginally interpret them. The behaviour of PS 5.0 seems to be different but
- # ignore that for now. If any of the provided arguments has a space in it, powershell checks
- # the first and last character to ensure that they are " characters (and that's all it checks).
- # If they are not, it will blindly surround that argument with " characters. It won't do this
- # operation if no space is present, even if other special characters are present. If it notices
- # leading and trailing " characters, it won't actually check to see if there are other "
- # characters in the string. Since PS 5.0 changes this behavior, we could consider using the --%
- # "stop screwing up my arguments" operator, which is available since PS 3.0. When encountered
- # --% indicates that the rest of line is to be sent literally... except if the parser encounters
- # %FOO% cmd style environment variables. Because reasons. And there is no way to escape the
- # % character in *any* waym shape or form.
- # https://connect.microsoft.com/PowerShell/feedback/details/376207/executing-commands-which-require-quotes-and-variables-is-practically-impossible
- #
- # In case you think that you're either reading this incorrectly or that I'm full of shit, here
- # are some examples. These use EchoArgs.exe from the PowerShell Community Extensions package.
- # I have not included the argument parsing output from EchoArgs.exe to prevent confusing you with
- # more details about MSVCRT's parsing algorithm.
- #
- # $x = "foo '' bar `"baz`""
- # & EchoArgs @($x, $x)
- # Command line:
- # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" "foo '' bar "baz"" "foo '' bar "baz""
- #
- # $x = "abc'123'nospace`"lulz`"!!!"
- # & EchoArgs @($x, $x)
- # Command line:
- # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" abc'123'nospace"lulz"!!! abc'123'nospace"lulz"!!!
- #
- # $x = "`"`"Look ma! Tonnes of spaces! 'foo' 'bar'`"`""
- # & EchoArgs @($x, $x)
- # Command line:
- # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" ""Look ma! Tonnes of spaces! 'foo' 'bar'"" ""Look ma! Tonnes of spaces! 'foo' 'bar'""
- #
- # Given all this, we can now device a strategy to work around all these immensely helpful, well
- # documented and useful tools by looking at each incoming argument, escaping any ' characters
- # with a '"'"' sequence, surrounding each argument with ' & joining them with a space separating
- # them.
- # There is another bug (https://bugs.ruby-lang.org/issues/11142) that causes ruby to mangle any
- # "" two-character double quote sequence but since we always emit our strings inside ' except for
- # ' characters, this should be ok. Just remember that an argument '' should get translated to
- # ''"'"''"'"'' on the command line. If those intervening empty ''s are not present, the presence
- # of "" will cause ruby to mangle that argument.
- $transformedList = $argList | foreach { "'" + ( $_ -replace "'","'`"'`"'" ) + "'" }
- $fortifiedArgString = $transformedList -join ' '
-
- # Use the correct embedded ruby path. We'll be deployed at a path that looks like
- # [C:\opscode or some other prefix]\chef\modules\chef
- $ruby = Join-Path (Get-ScriptDirectory) "..\..\embedded\bin\ruby.exe"
- $commandPath = Join-Path (Get-ScriptDirectory) "..\..\bin\$command"
-
- Run-ExecutableAndWait $ruby """$ruby"" '$commandPath' $fortifiedArgString"
-}
-
-
-function chef-apply {
- Run-RubyCommand 'chef-apply' $args
-}
-
-function chef-client {
- Run-RubyCommand 'chef-client' $args
-}
-
-function chef-service-manager {
- Run-RubyCommand 'chef-service-manager' $args
-}
-
-function chef-shell {
- Run-RubyCommand 'chef-shell' $args
-}
-
-function chef-solo {
- Run-RubyCommand 'chef-solo' $args
-}
-
-function chef-windows-service {
- Run-RubyCommand 'chef-windows-service' $args
-}
-
-function knife {
- Run-RubyCommand 'knife' $args
-}
-
-Export-ModuleMember -function chef-apply
-Export-ModuleMember -function chef-client
-Export-ModuleMember -function chef-service-manager
-Export-ModuleMember -function chef-shell
-Export-ModuleMember -function chef-solo
-Export-ModuleMember -function chef-windows-service
-Export-ModuleMember -function knife
-
-# To debug this module, uncomment the line below
-# Export-ModuleMember -function Run-RubyCommand
-
-# Then run the following to reload the module. Use puts_argv as a helpful debug executable.
-# Remove-Module chef
-# Import-Module chef
-# "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args -Encoding ASCII
-# Copy-Item C:\opscode\chef\bin\ohai.bat C:\opscode\chef\bin\puts_args.bat
-# Run-RubyCommand puts_args 'Here' "are" some '"very interesting"' 'arguments[to]' "`"try out`""