DockerMachine.psm1
<#
.Synopsis Create new, list or load existing Docker Machine environments. #> #region Init Module $ErrorActionPreference = "Stop"; $DEFAULT_PORT = '443'; Try { & docker-machine | Out-Null } Catch { throw "docker-machine is not installed" } #endregion #region Private Functions function Get-ConfigTemplate ($targetHost, $envName, $envDir) { # Generate target address $targetHost = $targetHost -replace 'tcp://',''; if ($targetHost.Contains(':')) { $targetAddress = $targetHost; $targetHost = $targetHost.Split(':')[0]; } else { $targetAddress = "${targetHost}:${DEFAULT_PORT}"; } # Return config return @" { "ConfigVersion": 3, "Driver": { "IPAddress": "$targetHost", "MachineName": "$envName", "SSHUser": "", "SSHPort": 0, "SSHKeyPath": "", "SwarmMaster": false, "SwarmHost": "", "SwarmDiscovery": "", "URL": "tcp://${targetAddress}" }, "DriverName": "none", "HostOptions": { "Driver": "", "Memory": 0, "Disk": 0, "EngineOptions": { "ArbitraryFlags": [], "Dns": null, "GraphDir": "", "Env": [], "Ipv6": false, "InsecureRegistry": [], "Labels": [], "LogLevel": "", "StorageDriver": "", "SelinuxEnabled": false, "TlsVerify": true, "RegistryMirror": [], "InstallURL": "https://get.docker.com" }, "SwarmOptions": { "IsSwarm": false, "Address": "", "Discovery": "", "Agent": false, "Master": false, "Host": "tcp://0.0.0.0:3376", "Image": "swarm:latest", "Strategy": "spread", "Heartbeat": 0, "Overcommit": 0, "ArbitraryFlags": [], "ArbitraryJoinFlags": [], "Env": null, "IsExperimental": false }, "AuthOptions": { "CertDir": "$($envDir -replace '\\', '\\')", "CaCertPath": "$($envDir -replace '\\', '\\')\\ca.pem", "CaCertRemotePath": "", "ClientKeyPath": "$($envDir -replace '\\', '\\')\\key.pem", "ServerCertRemotePath": "", "ServerKeyRemotePath": "", "ClientCertPath": "$($envDir -replace '\\', '\\')\\cert.pem", "ServerCertSANs": [], "StorePath": "$($envDir -replace '\\', '\\')" } }, "Name": "$envName" } "@ } #endregion #region Public Functions function New-DockerMachine { <# .Synopsis Create new Docker Machine environment. .Description Creates new Docker Machine environment. .Parameter Name Name of the environment. .Parameter TargetHost Hostname of a Docker host. If no port is specified, default port 443 is used. Specify a custom port like this: "host.example.com:2376" .Parameter ClientBundleFile Client bundle file you downloaded from UCP. Not required if parameters -RootCaPemFile, -KeyPemFile, and -CertPemFile are used. .Parameter RootCaPemFile Root CA file in PEM format. Not required if parameter -ClientBundleFile is used. .Parameter KeyPemFile Private key file in PEM format. Not required if parameter -ClientBundleFile is used. .Parameter CertPemFile Certificate file in PEM format. Not required if parameter -ClientBundleFile is used. .Example # Create new environment 'example'. Access Docker API with TLS on host.example.com:443. Certificates from given client bundle will be used. New-DockerMachine -name example -TargetHost host.example.com -ClientBundleFile .\ucp-bundle-user.zip .Example # Create new environment 'example'. Access Docker API with TLS on host.example.com:2376, not to default port 443. Certificates from given client bundle will be used. New-DockerMachine -name example -TargetHost "host.example.com:2376" -ClientBundleFile .\ucp-bundle-user.zip .Example # Create new environment 'example'. Access Docker API with TLS on host.example.com:443. Instead of a client bundle three separate certificate files in PEM format will be used. New-DockerMachine -Name example -TargetHost host.example.com -RootCaPemFile .\cafile.pem -KeyPemFile .\keyfile.pem -CertPemFile .\certfile.pem .Example # Another scenario is possible: your IT department handles the certificate management for your Docker hosts. You send them your CSR and receive a custom client bundle. # That client bundle contains the root CA and the public certificate files, but not the private key file you created together with your CSR. # For Docker Machine to work, you additionally have to specify the key file. Should the client bundle contain a key file after all, it will be overwritten. New-DockerMachine -name example -TargetHost host.example.com -ClientBundleFile .\ucp-bundle-user.zip -KeyPemFile .\keyfile.pem #> [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] Param ( [Parameter(Mandatory=$True)][string]$Name, [Parameter(Mandatory=$True)][string]$TargetHost, [ValidateScript({Test-Path -Path $_ -PathType Leaf})][Parameter(Mandatory=$False)][string]$ClientBundleFile, [ValidateScript({Test-Path -Path $_ -PathType Leaf})][Parameter(Mandatory=$False)][string]$RootCaPemFile, [ValidateScript({Test-Path -Path $_ -PathType Leaf})][Parameter(Mandatory=$False)][string]$CertPemFile, [ValidateScript({Test-Path -Path $_ -PathType Leaf})][Parameter(Mandatory=$False)][string]$KeyPemFile ) $dockerMachineDir = Join-Path -Path $env:USERPROFILE -ChildPath ".docker\machine" $dockerMachinesDir = Join-Path -Path $dockerMachineDir -ChildPath "machines" $dockerEnvDir = Join-Path -Path $dockerMachinesDir -ChildPath $Name $dockerEnvConfig = Join-Path -Path $dockerEnvDir -ChildPath "config.json"; $dockerEnvRootCa = Join-Path -Path $dockerEnvDir -ChildPath "ca.pem"; $dockerEnvKey = Join-Path -Path $dockerEnvDir -ChildPath "key.pem"; $dockerEnvCert = Join-Path -Path $dockerEnvDir -ChildPath "cert.pem"; if (Test-Path -Path $dockerEnvDir -PathType Container) { Write-Warning "The environment `"$Name`" already exists at `"$dockerMachinesDir`". It must be removed first."; Remove-Item -Path $dockerEnvDir -Confirm:$true -Recurse -Force; if (Test-Path -Path $dockerEnvDir -PathType Container) { Write-Warning "Old environment was not removed. Exiting..."; exit 1; } } Write-Output "Creating environment at `"$dockerEnvDir`"" if ($PSCmdlet.ShouldProcess($dockerEnvDir, "Create directory")) { New-Item -ItemType Directory -Path $dockerEnvDir | Out-Null; } try { Write-Verbose "Extract/copy certificates"; if ($PSCmdlet.ShouldProcess($dockerEnvDir, "Extract/copy certificates")) { if ($ClientBundleFile -ne "") { Expand-Archive $ClientBundleFile -DestinationPath $dockerEnvDir; } # BUG: Nicht mit relativem Pfad if ($RootCaPemFile -ne "") { Copy-Item -Path $RootCaPemFile -Destination $dockerEnvRootCa -Confirm:$false; } if ($KeyPemFile -ne "") { Copy-Item -Path $CertPemFile -Destination $dockerEnvKey -Confirm:$false; } if ($CertPemFile -ne "") { Copy-Item -Path $KeyPemFile -Destination $dockerEnvCert -Confirm:$false; } if ((Test-Path -Path $dockerEnvRootCa -PathType Leaf) -and (Test-Path -Path $dockerEnvKey -PathType Leaf) -and (Test-Path -Path $dockerEnvCert -PathType Leaf)) { Write-Verbose "Certificates extracted/copied successfully"; } else { throw "Certificate(s) missing. Make sure to pass a valid client bundle file with parameter -ClientBundleFile or pass individual certificate files in PEM format with parameters -RootCaPemFile, -KeyPemFile, and -CertPemFile."; } } Write-Verbose "Generating docker config.json" $configTemplate = Get-ConfigTemplate -targetHost $TargetHost -envName $Name -envDir $dockerEnvDir; if ($PSCmdlet.ShouldProcess($dockerEnvDir, "Write config file")) { $configTemplate | Set-Content $dockerEnvConfig; } Write-Output "Environment `"$Name`" is now ready." Write-Output "Type `"Use-DockerMachine $Name`" to switch to that environment." Write-Warning "Be careful when interacting with a remote environment." } catch { Write-Verbose "Cleanup ${$dockerEnvDir}"; Remove-Item -Path $dockerEnvDir -Recurse -Force throw $_; } } function Use-DockerMachine { <# .Synopsis Use Docker Machine environment. .Description Use Docker Machine environment. Afterwards you can type Docker commands for this host/swarm. .Parameter Name Name of the environment. .Example # Use environment "test": New-DockerMachine test .Example # Use local Docker host: New-DockerMachine local #> Param( [Parameter(Mandatory=$True)][string]$Name ) if ($Name -eq "local" -or $Name -eq "default") { if (Test-Path Env:\\DOCKER_HOST) { Remove-Item Env:\\DOCKER_TLS_VERIFY; Remove-Item Env:\\DOCKER_HOST; Remove-Item Env:\\DOCKER_CERT_PATH; Remove-Item Env:\\DOCKER_MACHINE_NAME; } } else { Try { $dmDockerHost = docker-machine url $Name 2>&1; } Catch { throw "Docker Machine environment '${Name}' does not exist!"; exit 1; } [System.Environment]::SetEnvironmentVariable("DOCKER_TLS_VERIFY", "1", "Process"); [System.Environment]::SetEnvironmentVariable("DOCKER_HOST", $dmDockerHost, "Process"); [System.Environment]::SetEnvironmentVariable("DOCKER_CERT_PATH", "$env:userprofile\.docker\machine\machines\$Name", "Process"); [System.Environment]::SetEnvironmentVariable("DOCKER_MACHINE_NAME", $Name, "Process"); [System.Environment]::SetEnvironmentVariable("COMPOSE_CONVERT_WINDOWS_PATHS", "true", "Process"); } } function Get-DockerMachine { <# .Synopsis Get list of Docker Machine environments. .Description Get list of currently configured Docker Machine environments. .Example Get-DockerMachines #> & docker-machine ls -q } function Remove-DockerMachine { <# .Synopsis Remove Docker Machine environment. .Description Remove Docker Machine environment. .Parameter Name Name of the environment. .Example # Remove environment "test": Remove-DockerMachine test #> [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] Param( [Parameter(Mandatory=$True)][string]$Name ) if ($PSCmdlet.ShouldProcess($Name, "docker-machine rm")) { & docker-machine rm -y $Name; } } #endregion #region Export Module Members Export-ModuleMember -Function ("New-DockerMachine", "Use-DockerMachine", "Get-DockerMachine", "Remove-DockerMachine"); #endregion |