Skip to content

Commit

Permalink
TP4 and Nano compatible, HyperV Container support, Container Hostname…
Browse files Browse the repository at this point in the history
… support
  • Loading branch information
bgelens committed Dec 14, 2015
1 parent f003f2f commit b27c3b8
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 57 deletions.
14 changes: 10 additions & 4 deletions Configuration.ps1
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
configuration NewContainer {
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1

cWindowsContainer MyAppContainer {
Ensure = 'Present'
Name = 'MyAppContainer'
StartUpScript = '"Hello World" | out-file c:\hello.txt'
ContainerImageName = 'NanoServer'
}
}
NewContainer
Expand All @@ -14,12 +15,15 @@ configuration MultiLineConfigContainer {
param (
[String] $StartupScript
)
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1

cWindowsContainer MyDCContainer {
Ensure = 'Present'
Name = 'MyDCContainer'
StartUpScript = $StartupScript
ContainerImageName = 'NanoServer'
ContainerType = 'HyperV'
ContainerComputerName = 'MyContainer'
}
}

Expand All @@ -33,11 +37,12 @@ Start-DscConfiguration .\MultiLineConfigContainer -Wait -Verbose


configuration RemContainer {
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1

cWindowsContainer MyAppContainer {
Ensure = 'Absent'
Name = 'MyAppContainer'
ContainerImageName = 'NanoServer'
}
}
RemContainer
Expand All @@ -47,13 +52,14 @@ configuration ContainerNginX {
param (
[String] $StartupScript
)
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1

cWindowsContainer NginX {
Ensure = 'Present'
Name = 'NginX'
StartUpScript = $StartupScript
SwitchName = 'Virtual Switch'
ContainerImageName = 'WindowsServerCore'
}
}

Expand Down
34 changes: 22 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,46 @@ cWindowsContainer

Class Based DSC resource to deploy Windows Containers.

**Deploy container from default image with single line startup script**
**Update Sep 2015**
Get-DscConfiguration now shows ContainerId and currently assigned IP Address
![Config](https://github.com/bgelens/cWindowsContainer/blob/master/GetDSCConfigIPandID.jpg)
**Update Dec 2015**
Resource updated for TP4 (TP3 must use version 1.0).
Now supports HyperV container type and the defining of the hostname within the container.
Validated Nano Server compatibility

**Deploy container from Nano image with single line startup script**
```powershell
configuration NewContainer {
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1
cWindowsContainer MyAppContainer {
Ensure = 'Present'
Name = 'MyAppContainer'
StartUpScript = '"Hello World" | out-file c:\hello.txt'
ContainerImageName = 'NanoServer'
}
}
NewContainer
Start-DscConfiguration .\NewContainer -Wait -Verbose
```
![Config](https://github.com/bgelens/cWindowsContainer/blob/master/newcontainerconfig.jpg)

**Deploy container from default image with multi-line startup script**
**Deploy container from Nano image with multi-line startup script and specifying Container Hostname**
````powershell
configuration MultiLineConfigContainer {
param (
[String] $StartupScript
)
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1
cWindowsContainer MyDCContainer {
Ensure = 'Present'
Name = 'MyDCContainer'
StartUpScript = $StartupScript
ContainerImageName = 'NanoServer'
ContainerType = 'HyperV'
ContainerComputerName = 'MyContainer'
}
}
Expand All @@ -46,29 +58,31 @@ Start-DscConfiguration .\MultiLineConfigContainer -Wait -Verbose
**Remove container**
```powershell
configuration RemContainer {
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1
cWindowsContainer MyAppContainer {
Ensure = 'Absent'
Name = 'MyAppContainer'
ContainerImageName = 'NanoServer'
}
}
RemContainer
Start-DscConfiguration .\RemContainer -Wait -Verbose
```
**NGINX install and Network**
**NGINX install and Network (does not work on Nano as Invoke-WebRequest is not available)**
```powershell
configuration ContainerNginX {
param (
[String] $StartupScript
)
Import-DscResource -ModuleName cWindowsContainer
Import-DscResource -ModuleName cWindowsContainer -ModuleVersion 1.1
cWindowsContainer NginX {
Ensure = 'Present'
Name = 'NginX'
StartUpScript = $StartupScript
SwitchName = 'Virtual Switch'
ContainerImageName = 'WindowsServerCore'
}
}
Expand All @@ -82,8 +96,4 @@ Start-Process nginx
ContainerNginX -StartupScript $script
Start-DscConfiguration .\ContainerNginX -Wait -Verbose -Force
```
**Update**
Get-DscConfiguration now shows ContainerId and currently assigned IP Address
![Config](https://github.com/bgelens/cWindowsContainer/blob/master/GetDSCConfigIPandID.jpg)
```
5 changes: 2 additions & 3 deletions cWindowsContainer.psd1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Module manifest for module 'NewManifest'
# Module manifest for module 'cWindowsContainer'
#
# Generated by: Ben Gelens
#
Expand All @@ -12,7 +12,7 @@
RootModule = 'cWindowsContainer.psm1'

# Version number of this module.
ModuleVersion = '1.0'
ModuleVersion = '1.1'

# ID used to uniquely identify this module
GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'
Expand Down Expand Up @@ -120,4 +120,3 @@ HelpInfoURI = 'https://github.com/bgelens/cWindowsContainer'
# DefaultCommandPrefix = ''

}

124 changes: 86 additions & 38 deletions cWindowsContainer.psm1
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
enum Ensure {
Absent;
Present;
Absent
Present
}

enum ContainerType {
Default
HyperV
}

[DscResource()]
Expand All @@ -11,8 +16,14 @@ class cWindowsContainer {
[DscProperty(Mandatory)]
[Ensure] $Ensure

[DscProperty(Mandatory)]
[String] $ContainerImageName

[DscProperty()]
[String] $ContainerImage = 'WindowsServerCore'
[String] $ContainerImagePublisher

[DscProperty()]
[String] $ContainerImageVersion

[DscProperty()]
[String] $SwitchName
Expand All @@ -26,71 +37,108 @@ class cWindowsContainer {
[DscProperty(NotConfigurable)]
[String] $ContainerId

[DscProperty()]
[String] $ContainerComputerName

[DscProperty()]
[ContainerType] $ContainerType = [ContainerType]::Default

[void] Set () {
$ErrorActionPreference = 'Stop'
try {
if ($this.Ensure -eq [Ensure]::Present) {
Write-Verbose -Message 'Creating Container';
if ($null -eq ($Image = Get-ContainerImage -Name $this.ContainerImage)) {
Write-Error -Message "ContainerImage with name $($this.ContainerImage) was not found";
Write-Verbose -Message 'Starting creation of new Container'

#region start build New-Container parameters
$ContainerNewParams = [System.Collections.Hashtable]::new()
$ContainerNewParams.Add('Name',$this.Name)
$ContainerNewParams.Add('RuntimeType',$this.ContainerType)
if ($null -ne $this.ContainerComputerName) {
$ContainerNewParams.Add('ContainerComputerName',$this.ContainerComputerName)
}
#endregion start build New-Container parameters

$Params = @{
Name = $this.Name;
ContainerImage = $Image;
#region ContainerImage
$ContainerImageParams = [System.Collections.Hashtable]::new()
$ContainerImageParams.Add('Name',$this.ContainerImageName)
if ($null -ne $this.ContainerImagePublisher) {
$ContainerImageParams.Add('Publisher',$this.ContainerImagePublisher)
}
if ($null -ne $this.ContainerImageVersion) {
$ContainerImageParams.Add('Version',$this.ContainerImageVersion)
}
Write-Verbose -Message "Searching for image: $($ContainerImageParams | Out-String)"
if ($null -eq ($Image = Get-ContainerImage @ContainerImageParams)) {
Write-Error -Message "ContainerImage with properties $($ContainerImageParams | Out-String) was not found" -ErrorAction Stop
} else {
$ContainerNewParams.Add('ContainerImage',$Image)
}
#endregion ContainerImage

#region Switch
Write-Verbose -Message "Searching for specified switch: $($this.SwitchName)"
if ($this.SwitchName -and ($null -ne (Get-VMSwitch -Name $this.SwitchName))) {
Write-Verbose -Message 'VMSwitch was found and will be bound';
$Params += @{
SwitchName = $this.SwitchName;
}
Write-Verbose -Message 'Switch was found and will be bound'
$ContainerNewParams.Add('SwitchName',$this.SwitchName)
} elseif ($this.SwitchName -and ($null -eq (Get-VMSwitch -Name $this.SwitchName))) {
Write-Error -Message "VMSwitch with name $($this.SwitchName) was not found";
Write-Error -Message "Switch with name $($this.SwitchName) was not found" -ErrorAction Stop
}
$Container = New-Container @Params;
$Container | Start-Container | Out-Null;

#endregion Switch

#region Create and start Container
Write-Verbose -Message "Creating Container: $($ContainerNewParams | Out-String)"
$Container = New-Container @ContainerNewParams
$Container | Start-Container
#endregion Create and start Container

#region run startup script
if ($null -ne $this.StartUpScript) {
Write-Verbose -Message 'Startup Script specified, passing script to InvokeScript method'
[void] $this.InvokeScript(([scriptblock]::Create($this.StartUpScript)),$Container.ContainerId);
[void] $this.InvokeScript(([scriptblock]::Create($this.StartUpScript)),$Container.ContainerId)
}
#endregion run startup script
} else {
Write-Verbose -Message 'Removing Container';
Get-Container -Name $this.Name | Stop-Container -Passthru | Remove-Container -Force | Out-Null;
Write-Verbose -Message 'Removing Container'
Get-Container -Name $this.Name | Stop-Container -Passthru | Remove-Container -Force
}
} catch {
Write-Error -ErrorRecord $_ -ErrorAction Stop;
Write-Error -ErrorRecord $_ -ErrorAction Stop
}
}

[bool] Test () {
if ((Get-Container -Name $this.Name -ErrorAction SilentlyContinue) -and ($this.Ensure -eq [Ensure]::Present)) {
return $true;
return $true
} else {
return $false;
return $false
}
}

[String] InvokeScript ([String] $Script, [String] $ContainerId) {
$Output = Invoke-Command -ContainerId $ContainerId -RunAsAdministrator -ScriptBlock ([scriptblock]::Create($Script)) -ErrorAction SilentlyContinue;
return $Output;
$Output = Invoke-Command -ContainerId $ContainerId -RunAsAdministrator -ScriptBlock ([scriptblock]::Create($Script)) -ErrorAction Stop
return $Output
}

[cWindowsContainer] Get () {
$Configuration = [hashtable]::new();
$Configuration.Add('Name',$this.Name);
$Configuration.Add('ContainerImage',$this.ContainerImage);
$Configuration.Add('SwitchName',$this.SwitchName);
$Configuration.Add('StartUpScript',$this.StartUpScript);
$Configuration = [System.Collections.Hashtable]::new()
$Configuration.Add('Name',$this.Name)
$Configuration.Add('ContainerComputerName',$this.ContainerComputerName)
$Configuration.Add('ContainerImageName',$this.ContainerImageName)
$Configuration.Add('ContainerImagePublisher',$this.ContainerImagePublisher)
$Configuration.Add('ContainerImageVersion',$this.ContainerImageVersion)
$Configuration.Add('SwitchName',$this.SwitchName)
$Configuration.Add('StartUpScript',$this.StartUpScript)
$Configuration.Add('ContainerType',$this.ContainerType)
if (($this.Ensure -eq [Ensure]::Present) -and ($this.Test())) {
Write-Verbose -Message 'Acquiring ContainerId';
$Configuration.Add('ContainerId',(Get-Container -Name $this.Name).ContainerId);
$Configuration.Add('Ensure','Present');
Write-Verbose -Message 'Acquiring IPAddress';
$Configuration.Add('IPAddress',$this.InvokeScript('(Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual).IPAddress',$Configuration.ContainerId));
Write-Verbose -Message 'Acquiring ContainerId'
$Configuration.Add('ContainerId',(Get-Container -Name $this.Name).ContainerId)
$Configuration.Add('Ensure','Present')
Write-Verbose -Message 'Acquiring IPAddress'
if ($null -ne $this.SwitchName) {
$Configuration.Add('IPAddress',$this.InvokeScript('(Get-NetIPAddress -AddressFamily IPv4 -PrefixOrigin Manual).IPAddress',$Configuration.ContainerId))
}
} else {
$Configuration.Add('Ensure','Absent');
$Configuration.Add('Ensure','Absent')
}
return $Configuration;
return $Configuration
}
}

0 comments on commit b27c3b8

Please sign in to comment.