Skip to content

Commit

Permalink
add code, helpers, example and doc
Browse files Browse the repository at this point in the history
  • Loading branch information
coatico committed Oct 18, 2024
1 parent bc12eb0 commit b469696
Show file tree
Hide file tree
Showing 8 changed files with 690 additions and 368 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Added the possibility to add multiple targets for a single iscsi session
- Transferred ownership to DSCCommunity.org - Fixes [Issue #50](https://github.com/dsccommunity/iSCSIDsc/issues/50).
- Fix hash table style guideline violations.
- Added .gitattributes file to fix bug publishing examples - Fixes [Issue #40](https://github.com/PlagueHO/iSCSIDsc/issues/40).
Expand Down Expand Up @@ -61,6 +62,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2019 only - Fixes [Issue #68](https://github.com/dsccommunity/iSCSIDsc/issues/68).
- Removed unused ISNS feature from being installed for unit tests.

## [1.5.0.42] - 2024-10-18

### Changed

- Changed the iSCSIinitiator resource to allow for multiple targets for a iscsi session defined.

### Fixed

- Fixed pipeline by replacing the GitVersion task in the `azure-pipelines.yml`
Expand Down
288 changes: 288 additions & 0 deletions Modules/iSCSIDsc.ResourceHelper/iSCSIDsc.ResourceHelper.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
<#
.SYNOPSIS
Tests if the current machine is a Nano server.
#>
function Test-IsNanoServer
{
if (Test-Command -Name Get-ComputerInfo)
{
$computerInfo = Get-ComputerInfo

if ("Server" -eq $computerInfo.OsProductType `
-and "NanoServer" -eq $computerInfo.OsServerLevel)
{
return $true
}
}

return $false
}

<#
.SYNOPSIS
Tests if the the specified command is found.
#>
function Test-Command
{
param
(
[Parameter()]
[String]
$Name
)

return ($null -ne (Get-Command -Name $Name -ErrorAction Continue 2> $null))
}

<#
.SYNOPSIS
Creates and throws an invalid argument exception
.PARAMETER Message
The message explaining why this error is being thrown
.PARAMETER ArgumentName
The name of the invalid argument that is causing this error to be thrown
#>
function New-InvalidArgumentException
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$ArgumentName
)

$argumentException = New-Object -TypeName 'ArgumentException' -ArgumentList @( $Message,
$ArgumentName )
$newObjectParams = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @( $argumentException, $ArgumentName, 'InvalidArgument', $null )
}
$errorRecord = New-Object @newObjectParams

throw $errorRecord
}

<#
.SYNOPSIS
Creates and throws an invalid operation exception
.PARAMETER Message
The message explaining why this error is being thrown
.PARAMETER ErrorRecord
The error record containing the exception that is causing this terminating error
#>
function New-InvalidOperationException
{
[CmdletBinding()]
param
(
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]
$Message,

[Parameter()]
[ValidateNotNull()]
[System.Management.Automation.ErrorRecord]
$ErrorRecord
)

if ($null -eq $Message)
{
$invalidOperationException = New-Object -TypeName 'InvalidOperationException'
}
elseif ($null -eq $ErrorRecord)
{
$invalidOperationException =
New-Object -TypeName 'InvalidOperationException' -ArgumentList @( $Message )
}
else
{
$invalidOperationException =
New-Object -TypeName 'InvalidOperationException' -ArgumentList @( $Message,
$ErrorRecord.Exception )
}

$newObjectParams = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @( $invalidOperationException.ToString(), 'MachineStateIncorrect',
'InvalidOperation', $null )
}
$errorRecordToThrow = New-Object @newObjectParams
throw $errorRecordToThrow
}

<#
.SYNOPSIS
Retrieves the localized string data based on the machine's culture.
Falls back to en-US strings if the machine's culture is not supported.
.PARAMETER ResourceName
The name of the resource as it appears before '.strings.psd1' of the localized string file.
For example:
For WindowsOptionalFeature: DSR_xWindowsOptionalFeature
For Service: DSR_xServiceResource
For Registry: DSR_xRegistryResource
.PARAMETER ResourcePath
The path the resource file is located in.
#>
function Get-LocalizedData
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$ResourceName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$ResourcePath
)

$localizedStringFileLocation = Join-Path -Path $ResourcePath -ChildPath $PSUICulture

if (-not (Test-Path -Path $localizedStringFileLocation))
{
# Fallback to en-US
$localizedStringFileLocation = Join-Path -Path $ResourcePath -ChildPath 'en-US'
}

Import-LocalizedData `
-BindingVariable 'localizedData' `
-FileName "$ResourceName.strings.psd1" `
-BaseDirectory $localizedStringFileLocation

return $localizedData
}
function Get-ISCSIPersistentTarget() {
# This functions uses iscsli to get a persistent target based on the targetporalIP, targetportnumber & the targetnodeaddres.
# The result is returned as a hashtable with as key the targetportalip_nodeaddress = $hashofiscslipersistenttarget info
param(
[Parameter(Mandatory = $true)]
[ValidatePattern("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")]
[String]$targetPortalIpAddress,
[Parameter(Mandatory = $true)]
[ValidatePattern("^\d{4}$")]
[int]$targetPortNumber,
[Parameter(Mandatory = $true)]
[ValidatePattern("^iqn\.(\d{4}-\d{2})\.([a-zA-Z0-9]+\.[a-zA-Z0-9]+):([a-zA-Z0-9\.]+)$")]
[String]$targetNodeAddress
)
#escape the . character in the ip address
$escapedIP = $targetPortalIpAddress -replace '\.', '\.'
#query iscscli for persistent targets
$iscsi = "iscsicli listpersistenttargets | Select-String -Pattern `"\s*Address and Socket\s*:\s*($escapedIP)\s+(\d+)`" -Context 1, 10"
$search = invoke-expression $iscsi
$return = @{}
foreach ($matchObject in $search) {
$blob = ($matchObject[0].Context.PreContext + $matchObject[0].Line.TrimStart('--') + $matchObject[0].Context.PostContext) -join "`n" | out-string
# Convert $blob to hashtable
$hashtable = @{}
$lines = $blob -split "`n"
foreach ($line in $lines) {
if ($line -match ':') {
$parts = $line.Split(':', 2)
if ($parts[1].Trim() -ne '') {
$hashtable[$parts[0].Trim()] = $parts[1].Trim()
}
}
}
[String]$key = "$targetPortalIpAddress`_$($hashtable.'Target Name')"
if ($targetNodeAddress -eq $hashtable.'Target Name') { $return[$key] = $hashtable }
}
return $return
}

function Remove-ISCSIPersistentTarget() {
# This function will remove the persistent iscsi targets based on targetporalIP, targetportnumber & the targetnodeaddres.
param(
[Parameter(Mandatory = $true)]
[ValidatePattern("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")]
[String]$targetPortalIpAddress,
[Parameter(Mandatory = $true)]
[ValidatePattern("^\d{4}$")]
[int]$targetPortNumber,
[Parameter(Mandatory = $true)]
[ValidatePattern("^iqn\.(\d{4}-\d{2})\.([a-zA-Z0-9]+\.[a-zA-Z0-9]+):([a-zA-Z0-9\.]+)$")]
[String]$targetNodeAddress
)
#build the iscsicli command
$peristentTargetSearch = get-iSCSIPersistentTarget -targetPortalIpAddress $targetPortalIpAddress -targetPortNumber $targetPortNumber -targetNodeAddress $targetNodeAddress
foreach ($result in $peristentTargetSearch) {
$result.value
$iscsi = "iscsicli removepersistenttarget $($result.values.'Initiator Name') $($result.values.'Target Name') $($result.values.'Port Number') $($result.values.'Address and Socket')"
write-verbose "iscsicli command == $iscsi"
invoke-expression $iscsi
}
}

function Get-ISCSICLIListSessions() {
# This functions uses iscsli to get a persistent target based on the targetporalIP, targetportnumber & the targetnodeaddres.
# The result is returned as a hashtable with as key the targetportalip_nodeaddress = $hashofiscslipersistenttarget info
param(
[Parameter(Mandatory = $true)]
[ValidatePattern("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")]
[String]$targetPortalIpAddress,
[Parameter(Mandatory = $true)]
[ValidatePattern("^\d{4}$")]
[int]$targetPortNumber,
[Parameter(Mandatory = $true)]
[ValidatePattern("^iqn\.(\d{4}-\d{2})\.([a-zA-Z0-9]+\.[a-zA-Z0-9]+):([a-zA-Z0-9\.]+)$")]
[String]$targetNodeAddress,
[Parameter(Mandatory = $false)]
[ValidatePattern("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")]
[String]$initiatorPortalIpAddress
)
#escape the . character in the ip address
$escapedTargetIP = $targetPortalIpAddress -replace '\.', '\.'
#query iscscli for persistent targets
$iscsi = "iscsicli sessionlist | Select-String -Pattern `"\s*Target\sPortal\s*:\s*($escapedTargetIP)\/($targetPortNumber)`" -Context 12, 1"
$search = invoke-expression $iscsi
$return = @{}
foreach ($matchObject in $search) {
$blob = ($matchObject[0].Context.PreContext + $matchObject[0].Line.TrimStart('--') + $matchObject[0].Context.PostContext) -join "`n" | out-string
# Convert $blob to hashtable
$hashtable = @{}
$lines = $blob -split "`n"
foreach ($line in $lines) {
if ($line -match ':') {
$parts = $line.Split(':', 2)
if ($parts[1].Trim() -ne '') {
$hashtable[$parts[0].Trim()] = $parts[1].Trim()
}
}
}
if ($targetNodeAddress -eq $hashtable.'Target Name' -and $hashtable.'Initiator Portal' -match "$initiatorPortalIpAddress\/\d+" ) {
$hashtable['initiatorPortalIpAddress']= $initiatorPortalIpAddress
$hashtable['targetPortalIpAddress'] = $targetPortalIpAddress
[String]$key = "$targetPortalIpAddress`_$($hashtable.'Target Name')"
$return[$key] = $hashtable
}
}
return $return
}

Export-ModuleMember -Function @(
'Test-IsNanoServer',
'New-InvalidArgumentException',
'New-InvalidOperationException',
'Get-LocalizedData',
'Get-ISCSIPersistentTarget',
'Remove-ISCSIPersistentTarget',
'Get-ISCSICLIListSessions'
)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ The **iSCSIDsc** module contains DSC resources for configuring Windows iSCSI
Targets and Initiators.

- **iSCSIInitiator**: This resource is used to add or remove an iSCSI Target
Portal and connect it to an iSCSI Target.
Portal and connect it to an iSCSI Target (with multiple targets defined possible).
- **iSCSIServerTarget**: This resource is used to create or remove Virtual Disks
for use by iSCSI Targets.
- **iSCSIVirtualDisk**: This resource is used to create or remove Virtual Disks
Expand Down
Loading

0 comments on commit b469696

Please sign in to comment.