I actually thought I’d posted this (NFS_Exports_7toC
v1.1), and then looking back realized I hadn’t, just an old version exists
(August 2015’s How
to Convert 7-Mode NFS Exports into cDOT Export Policies and Rules.) There
are maybe a few more 7 to C skirmishes still left to do, so perhaps there might
still be some use to be had in this tool.
This is the best version of my NFS Exports 7 to C
translator/converter (apologies if the code is a bit clunky). Copy and paste
the below script into a text editor and save as NFS_Exports_7toC.ps1. Then simply run in PowerShell as::>
.\NFS_Exports_7toC.ps1
-FilePath {exports_file}
Image: Example of
running NFS_Exports_7toC
The Script
#############################
##
NFS EXPORTS 7 to C v1.1 ##
#############################
Param(
[Parameter(Mandatory=$true)][String]$FilePath, # 7-Mode Exports File
[String]$VserverName = "SVM1", #
cDOT: Vserver Name
[System.Array]$OverrideQtrees # Specify a
list as - "vol1.folder1","vol2.folder2",... - where ??? in
the path /vol/VOLNAME/??? is not a Qtree
)
[String]$FileName
= $FilePath.Split("\")[0] # We use the FileName in some outputs
[String]$Global:LOut
= "" # Record lines of Screen Output, which are flushed to SOut on Wr
[System.Array]$Global:SOut
= @() # Used to record the ScreenOutput
Function
Wr {
Param([String]$DisplayThis,[String]$ForegroundColor)
If(!$DisplayThis){ Write-Host; $Global:SOut
+= $Global:LOut; $Global:LOut = ""; RETURN }
elseif(!$ForegroundColor){ Write-Host
$DisplayThis -ForegroundColor White -NoNewLine }
else { Write-Host $DisplayThis
-ForegroundColor $ForegroundColor -NoNewLine }
$Global:LOut += $DisplayThis
};
Wr
Wr
"<<<<< NFS EXPORTS 7 to C v1.1 >>>>>"
MAGENTA; Wr; Wr
######################################
##
GET AND PROCESS THE EXPORTS FILE ##
######################################
[System.Array]$ExportsFile
= Get-Content $FilePath
Wr
"Loaded file from: $FilePath" GREEN; Wr
Function
Process-Array {
Param([System.Array]$ArrayToProcess)
[System.Array]$ProcessedArray = @()
Foreach ($Line in $ArrayToProcess){
## REMOVE BLANK LINES "" AND
LINES BEGINNING WITH "#" ##
If( ($Line -ne "") -and
($Line.substring(0,1) -ne "#") ){ $ProcessedArray += $Line }
}
, $ProcessedArray # RETURN THE PROCESSED
ARRAY
}
$ExportsFile
= Process-Array $ExportsFile; Wr
######################################################
##
STEP 1: PROCESS 7-MODE EXPORTS FILE LINE BY LINE ##
######################################################
Wr
">>> STEP 1: PLEASE VERIFY THAT THE EXPORTS FILE HAS BEEN READ
CORRECTLY! <<<" MAGENTA; Wr; Wr
Function
Process-ExportsLine {
Param([String]$Line)
##### SPLIT ON -actual= OR -sec= TO GET PATH
& OPTIONS BITS (VOLNAME,QTREE,SUBQTREE) #####
[System.Array]$SplitOnDashSec = $Line.Replace("-sec=","#").Split("#") # Expect (1)PATH_BIT[0]/(2)OPTIONS_BIT[1]
{OR}
[System.Array]$SplitOnDashActual =
$Line.Replace("-actual=","#").Split("#") # Expect
(1)PATH_BIT[0]/(2)OPTIONS_BIT[1]
If( !( ($SplitOnDashSec.Count -eq 2) -or
($SplitOnDashActual.Count -eq 2) ) ){ RETURN } # NOT A VALID LINE (
.LineIsValid remains FALSE)
If( $SplitOnDashSec.Count -eq 2 ){ ## HAS
-sec= ##
[String]$PathBit = $SplitOnDashSec[0].Trim("
","`t")
[String]$OptionsBit = $SplitOnDashSec[1].Trim("
","`t")
} else { ## HAS -actual= ##
$Exports.$Index.ActualSpecified = $TRUE
[String]$PathBit = $SplitOnDashActual[0].Trim("
","`t")
[String]$OptionsBit =
$SplitOnDashActual[1].Trim(" ","`t")
}
$SplitOnSlash = $PathBit.Split("/")
# Expect (1)[0]/(2)vol[1]/(3)VOLNAME[2]/(4){QTREE}[3]/{SUBQTREE_BIT}
If($SplitOnSlash.Count -lt 3){ RETURN } # NOT
A VALID LINE ( .LineIsValid remains FALSE)
[String]$VolNameFromExport = $SplitOnSlash[2]
$Exports.$Index.VolName = $VolNameFromExport
If($SplitOnSlash.Count -ge 4){
$PossibleQtree =
$SplitOnSlash[3].Replace("\"," ") # Qtrees names can have
" " in (which is \ in exports)
If( !($OverrideQtrees -contains
($VolNameFromExport + "." + $PossibleQtree)) ){
$Exports.$Index.QtreeName =
$PossibleQtree
}
}
If($SplitOnSlash.Count -ge 5){
[String]$PathUpToQtree = ("/vol/"
+ $Exports.$Index.VolName + "/" + $Exports.$Index.QtreeName +
"/")
$Exports.$Index.SubQtreeBit =
$PathBit.Substring($PathUpToQtree.Length).Replace("\"," ")
# Folder names can have " " in (which is \ in exports)
}
##### HANDLE THE OPTIONS #####
## -actual= COMES 1ST ##
If($Exports.$Index.ActualSpecified){
$Exports.$Index.ActualEquals =
$OptionsBit.Replace(",sec=","#").Split("#")[0]
$OptionsBit =
$OptionsBit.Replace(",sec=","#").Split("#")[1]
}
## -sec= COMES 2ND ##
$Exports.$Index.SecEquals =
$OptionsBit.Split(",")[0]
$OptionsBit =
$OptionsBit.TrimStart($Exports.$Index.SecEquals)
## THESE REST (all separated by ,) ##
$OptionsSplitComma =
$OptionsBit.Split(",") # Note: We left a comma after the sec= bit
For( [Int]$i=1; $i -lt
($OptionsSplitComma.Count); $i++ ){
[String]$CheckThis =
[String]($OptionsSplitComma[$i])
$CheckThis = $CheckThis.Trim("
","`t","`n")
If($CheckThis.StartsWith("anon=")){
$Exports.$Index.AnonSpecified = $TRUE }
If($CheckThis.StartsWith("anon=")){
$Exports.$Index.AnonEquals = $CheckThis.Substring(5) }
If($CheckThis -eq "nosuid") { $Exports.$Index.NoSuidSpecified =
$TRUE }
If($CheckThis -eq "ro") { $Exports.$Index.RoSpecified = $TRUE }
If($CheckThis.StartsWith("ro=")) { $Exports.$Index.RoEquals = $CheckThis.Substring(3) }
If($CheckThis -eq "rw") { $Exports.$Index.RwSpecified = $TRUE }
If($CheckThis.StartsWith("rw=")) { $Exports.$Index.RwEquals = $CheckThis.Substring(3) }
If($CheckThis.StartsWith("root=")){
$Exports.$Index.RootEquals =
$CheckThis.Substring(5) }
}
$Exports.$Index.LineIsValid = $TRUE # N.B.
Could do with adding some validity tests!
}
[Int]$Index
= 0 # INITIALIZE THE INDEX AS 0
[System.Object]$Exports
= @{} # INITIALIZE THE $Exports OBJECT
Foreach($Line
in $ExportsFile){
$Index++
## INITIALIZE THE OBJECT TO HOLD THE 7-MODE
EXPORT LINE'S DATA ##
[System.Object]$Exports.$Index = @{} # DATA STRUCTURE TO CONTAIN 7-MODE EXPORTS
[String]$Exports.$Index.VolName = "" # /vol/VOLNAME
[String]$Exports.$Index.QtreeName = "" # /vol/VOLNAME/QTREENAME
[String]$Exports.$Index.SubQtreeBit = "" # /vol/VOLNAME/QTREENAME/SUBQTREEBIT
[Boolean]$Exports.$Index.ActualSpecified = $FALSE # actual= is
specified
[String]$Exports.$Index.ActualEquals
= "" #
actual={path}
[Boolean]$Exports.$Index.AnonSpecified = $FALSE # anon= is specified
[String]$Exports.$Index.AnonEquals
= "" #
anon={uid|name}
[Boolean]$Exports.$Index.NoSuidSpecified = $FALSE # nosuid is specified
[Boolean]$Exports.$Index.RoSpecified
= $FALSE # ro is specified (with no equals)
[String]$Exports.$Index.RoEquals = "" # ro={clientid[:clientid...]}
[Boolean]$Exports.$Index.RwSpecified
= $FALSE # rw is specified (with no equals)
[String]$Exports.$Index.RwEquals = "" # rw={clientid[:clientid...]}
[String]$Exports.$Index.RootEquals
= "" #
root={clientid[:clientid...]}
[String]$Exports.$Index.SecEquals = "" # sec={sectype[:sectype...]}
[Boolean]$Exports.$Index.LineIsValid
= $FALSE # (... check exports line is valid ...)
[String]$Exports.$Index.OriginalLine
= "" # (... record
the line sent for processing ...)
# See:
https://library.netapp.com/ecmdocs/ECMP1196979/html/man5/na_exports.5.html
## GET RID OF ANY COMMENTS AT THE END OF THE
LINE AND TRIM SPACES AND TABS ##
$Exports.$Index.OriginalLine =
$Line.Split("#")[0].Trim(" ","`t")
## INVOKE THE PROCESS-EXPORTS FUNCTION TO
PROCESS THE EXPORTS LINE ##
Process-ExportsLine
($Exports.$Index.OriginalLine)
## DISPLAY THE PROCESSED LINE (TO MAKE SURE
WE'VE READ IT RIGHT!) ##
Wr "ORIGINAL LINE: "; Wr
$Exports.$Index.OriginalLine GREEN; Wr
If(!$Exports.$Index.LineIsValid){ Wr
"NOT A VALID LINE!" RED; Wr}
else{
Wr
"Volume : "; Wr
$Exports.$Index.VolName CYAN; Wr
If($Exports.$Index.QtreeName){
If($OverrideQtrees){ Wr "Qtree : "; Wr
$Exports.$Index.QtreeName CYAN; Wr}
else { Wr "Qtree
"; Wr "(Assumed)" YELLOW; Wr ": "; Wr
$Exports.$Index.QtreeName CYAN; Wr}
}
If($Exports.$Index.SubQtreeBit) {Wr "SUBQTREE BIT : "; Wr $Exports.$Index.SubQtreeBit
CYAN; Wr}
If($Exports.$Index.ActualSpecified){Wr
"actual= : "; Wr
$Exports.$Index.ActualEquals CYAN; Wr}
Wr
"sec= : "; Wr
$Exports.$Index.SecEquals CYAN; Wr
If($Exports.$Index.RoSpecified) {Wr "RO : "; Wr "Specified as
ro!" YELLOW; Wr}
If($Exports.$Index.RoEquals) {Wr "RO HOSTS= : "; Wr $Exports.$Index.RoEquals
CYAN; Wr}
If($Exports.$Index.RwSpecified) {Wr "RW : "; Wr "Specified as rw!"
YELLOW; Wr}
If($Exports.$Index.RwEquals) {Wr "RW HOSTS= : "; Wr $Exports.$Index.RwEquals
CYAN; Wr}
If($Exports.$Index.RootEquals) {Wr "ROOT HOSTS= : "; Wr $Exports.$Index.RootEquals
CYAN; Wr}
If($Exports.$Index.AnonSpecified) {Wr "ANON = : "; Wr
$Exports.$Index.AnonEquals YELLOW; Wr}
If($Exports.$Index.NoSuidSpecified){Wr
"NOSUID : "; Wr
"Nosuid is specified." GREEN; Wr}
};Wr
}
#########################################################################
##
STEP 2: PROCESSING THE 7-MODE EXPORTS TO CDOT CLUSTERSHELL COMMANDS ##
#########################################################################
Wr
">>> STEP 2: PROCESSING THE 7-MODE EXPORTS TO CDOT CLUSTERSHELL
COMMANDS <<<" MAGENTA; Wr; Wr
##
CHECK FOR LINES WE CAN HANDLE ##
##
============================= ##
[System.Array]$VolExportsOnly = @() # Array for volume exports only -
/vol/VOLNAME
[System.Array]$SubVolExportsOnly = @() # Array for sub-volume exports only -
/vol/VOLNAME/SUB-FOLDER
[System.Array]$QtreeExportsOnly = @() # Array for qtree exports only -
/vol/VOLNAME/QTREENAME
[System.Array]$SubQtreeExportsOnly
= @() # Array for sub-qtree exports only -
/vol/VOLNAME/QTREENAME/SUB-QTREE-FOLDER
[System.Object]$cExports
= @{} # Initialize cExports object
[System.Array]$cExports.ExportedVolList
= @() # Create an array for the ExportedVolumeList
[System.Object]$cExports.Volume
= @{} # Create an object for volumes
##
CYCLE THROUGH THE 7-MODE EXPORTS ##
For($i=1;
$i -le $Index; $i++){
## CHECK FOR VALID EXPORTS LINE ##
If($Exports.$Index.LineIsValid){
## THINGS THIS PROGRAM DOESN'T HANDLE (YET)
##
If( $Exports.$i.ActualSpecified ){
Wr "-actual= IS NOT SUPPORTED IN
cDOT (see TR-4067)!" RED; Wr
Wr "WON'T HANDLE: " RED; Wr
$Exports.$i.OriginalLine YELLOW; Wr; Wr
} elseif( $Exports.$i.SecEquals -ne
"sys" ){
Wr "ONLY HANDLING SEC=SYS
EXPORTS!" RED; Wr
Wr "WON'T HANDLE: " RED; Wr
$Exports.$i.OriginalLine YELLOW; Wr; Wr
} else {
$VolName
= $Exports.$i.VolName
$QtreeName = $Exports.$i.QtreeName
## THINGS WE CAN PROCESS ##
If(
!$QtreeName -and !$Exports.$i.SubQtreeBit){$VolExportsOnly += $i} # 7M Exports that have NO Qtree
NOR a Sub-Qtree bit
elseif(!$QtreeName -and
$Exports.$i.SubQtreeBit){$SubVolExportsOnly += $i} # 7M Exports that have NO Qtree BUT a
Sub-Qtree (Sub-Volume) bit
elseif( $QtreeName -and
!$Exports.$i.SubQtreeBit){$QtreeExportsOnly
+= $i} # 7M Exports that have a Qtree and NO Sub-Qtree bit
elseif( $QtreeName -and $Exports.$i.SubQtreeBit){$SubQtreeExportsOnly
+= $i} # 7M Exports that have a Qtree and a Sub-Qtree bit
## WARN ABOUT SUB QTREE/SUB VOLUME
EXPORTS ##
If( $Exports.$i.SubQtreeBit ){
Wr "WARNING! THE FOLLOWING LINE IS
A SUB QTREE/SUB VOLUME (without a QTREE) EXPORT. " YELLOW
If($QtreeName){Wr "WILL DEFINE
RULES IN AN EXPORT POLICY ON THE QTREE." CYAN; Wr}
Else{Wr "WILL DEFINE RULES IN AN
EXPORT POLICY ON THE VOLUME." CYAN; Wr}
Wr "LINE: " CYAN; Wr
$Exports.$i.OriginalLine GREEN; Wr; Wr
}
## POPULATE EXPORTED VOLS LIST ##
If( !($cExports.ExportedVolList -Contains
$VolName) ){
$cExports.ExportedVolList += $VolName #
Accumulate the Exported Vols List
[System.Object]$cExports.Volume.$VolName = @{} # Create an object for this volume
[Boolean]$cExports.Volume.$VolName.HasQtreeExports
= $FALSE # Initialize as FALSE for has Qtree Exports
[System.Array]$cExports.Volume.$VolName.ExportedQtreeList = @() # Create
an array for exported qtrees for $VolName
}
## POPULATE EXPORTED QTREES LIST ##
If($QtreeName){
If(
!($cExports.Volume.$VolName.ExportedQtreeList -Contains $QtreeName) ){
$cExports.Volume.$VolName.ExportedQtreeList
+= $QtreeName
$cExports.Volume.$VolName.HasQtreeExports = $TRUE
}
}
}
}
}
##
INITIALIZE CLUSTERSHELL OUTPUT ##
##
============================== ##
[System.Array]$Output
= @()
$Output
+= ("### 7 TO C EXPORTS TRANSLATIONS for $FileName ###")
$Output
+= (""),("## VOLUME MOUNT FOR EXPORTED VOLUMES
##"),("")
$cExports.ExportedVolList
| Foreach { $Output += ("volume mount -vserver $VserverName -junction-path
/vol/$_") } # Mount Volumes
$Output
+= (""),("## CREATE NO ACCESS AND READONLY EXPORT POLICIES
(8.2+) ##"),("")
$Output
+= ("vserver export-policy create -vserver $VserverName -policyname
expol_noaccess") # No Access Export Policy
$Output
+= ("vserver export-policy create -vserver $VserverName -policyname
expol_readonly") # Read Only Export Policy
$Output
+= ("vserver export-policy rule create -vserver $VserverName -policyname
expol_readonly -ruleindex 1 -protocol any -clientmatch 0.0.0.0/0 -rorule any
-rwrule never -anon 65534 -superuser none -allow-suid true -allow-dev
true")
$Output
+= (""),("## INITIALLY APPLY READ ONLY TO ALL EXPORTED VOLUMES
##"),("")
$cExports.ExportedVolList
| Foreach { $Output += "volume modify -vserver $VserverName -volume $_
-policy expol_readonly" } # Initially apply readonly to all volumes
$Output
+= (""),("## INITIALLY APPLY NO ACCESS TO QTREES ON EXPORTED
VOLUMES ##"),("")
$cExports.ExportedVolList
| Foreach { $Output += ("qtree modify -vserver $VserverName -volume $_
-qtree !" + '"' + '"' + " -export-policy
expol_noaccess") } # Initially apply no access to all qtrees
$Output
+= ("")
##
FUNCTIONS TO FIX INCORRECT SUBNETS ON 7-MODE EXPORTS ##
##
==================================================== ##
Function
Find-OctetBit{
Param([Int]$Octet,[Int]$SubnetBit)
$ModuloOctet = $Octet
$ModuloOctet %= 256/([math]::Pow(2,$SubnetBit))
$Octet -= $ModuloOctet
RETURN $Octet
}
Function
Return-CorrectSubnet {
Param([String]$ClientMatch)
If($ClientMatch -match "/"){
[System.Array]$Octet =
$ClientMatch.Split("/")[0].Split(".")
If( $Octet.Count -ne 4 ){ RETURN
$ClientMatch }
[Int]$Subnet =
$ClientMatch.Split("/")[1]
If
($Subnet -ge 24){ $ClientMatch = $Octet[0] + "." + $Octet[1] +
"." + $Octet[2] + "." + [String](Find-OctetBit $Octet[3]
($Subnet -24)) + "/" + [String]$Subnet }
elseif ($Subnet -ge 16){ $ClientMatch =
$Octet[0] + "." + $Octet[1] + "." + [String](Find-OctetBit
$Octet[2] ($Subnet -16)) + ".0/" + [String]$Subnet }
elseif ($Subnet -ge 8) { $ClientMatch =
$Octet[0] + "." + [String](Find-OctetBit $Octet[1] ($Subnet -8)) +
".0.0/" + [String]$Subnet }
else { $ClientMatch =
[String](Find-OctetBit $Octet[0] ($Subnet -0)) + ".0.0.0/" +
[String]$Subnet }
}
RETURN $ClientMatch
}
##
FUNCTION TO PROCESS ROOT HOSTS, RW HOSTS, AND RO HOSTS ##
##
====================================================== ##
[System.Array]$Global:RwRules = @() # Initialize array for Read/Write
Rules (must come before ro rules)
[System.Array]$Global:RoRules = @() # Initialize array for Read/Only Rules
[System.Array]$Global:RwClients
= @() # Initialize array for RW Clients (used to prevent duplicates)
[System.Array]$Global:RoClients
= @() # Initialize array for RO Clients (used to prevent duplicates)
Function
Process-AllHosts {
Param([System.Object]$7mExport)
[System.Array]$RootHosts =
($7mExport.RootEquals).Split(":")
[System.Array]$RwHosts = ($7mExport.RwEquals).Split(":")
[System.Array]$RoHosts = ($7mExport.RoEquals).Split(":")
If($RwHosts){
Foreach ($RwHost in $RwHosts){
$RwHost = Return-CorrectSubnet $RwHost
If( !($Global:RwClients -Contains
$RwHost) ){
$Global:RwClients += $RwHost
If($RootHosts -Contains
$RwHost){$Global:RwRules += ("$DefaultProtocol -clientmatch $RwHost
-rorule sys -rwrule sys $Anon -superuser sys $Suid $DefaultDev")}
else{$Global:RwRules +=
("$DefaultProtocol -clientmatch $RwHost -rorule sys -rwrule sys $Anon
-superuser none $Suid $DefaultDev")}
}
}
}
If($RoHosts){
Foreach($RoHost in $RoHosts){
$RoHost = Return-CorrectSubnet $RoHost
If(!($Global:RoClients -Contains
$RoHost)){
$Global:RoClients += $RoHost
If($RootHosts -Contains
$RoHost){$Global:RoRules += ("$DefaultProtocol -clientmatch $RoHost
-rorule sys -rwrule never $Anon -superuser sys $Suid $DefaultDev")}
else{$Global:RoRules +=
("$DefaultProtocol -clientmatch $RoHost -rorule sys -rwrule never $Anon
-superuser none $Suid $DefaultDev")}
}
}
}
If($RootHosts){
Foreach ($RootHost in $RootHosts){
$RootHost = Return-CorrectSubnet
$RootHost
If( !($Global:RwClients -Contains
$RootHost) ){
If( !($RwHosts -contains $RootHost)
-and !($RoHosts -contains $RootHost) ){
$Global:RwClients += $RootHost
$Global:RwRules +=
("$DefaultProtocol -clientmatch $RootHost -rorule sys -rwrule sys $Anon
-superuser sys $Suid $DefaultDev")
}
}
}
}
Return $TRUE
}
##
CREATE AND APPLY PER VOLUME EXPORT POLICIES (INCLUDES SUB-VOLUME EXPORTS) ##
##
========================================================================= ##
[String]$DefaultProtocol
= "-protocol any" # Not
specified in 7-Mode
[String]$DefaultAnon = "-anon 65534" # Same default in 7-Mode (so, if not
specified is this)
[String]$DefaultSuid = "-allow-suid true" # Same
default in 7-Mode (so, if not specified is this)
[String]$DefaultDev = "-allow-dev true" # Same default in 7-Mode (so, if not
specified is this)
$Output
+= ("## PER VOLUME EXPORT POLICIES (INCLUDES SUB-VOLUME EXPORTS
##"),("")
Foreach($VolName
in $cExports.ExportedVolList){ # Cycle through the Exported Volumes List
[String]$ExPolicy = ("expol_v_" + $VolName)
[String]$ExPolRuleStart = "vserver export-policy rule
create -vserver $VserverName -policyname $ExPolicy -ruleindex " # Add rule
indexes later
[Boolean]$HasAVolOrSubVolExport = $FALSE
# Initialize "Has a Vol or Sub Vol Export (for $VolName) as FALSE
$Global:RwRules = @() # Reset R/W Rules
$Global:RoRules = @() # Reset R/O Rules
[String]$RwRule = "" # Initialize as NULL general Read/Write
rule
[String]$RoRule = "" # Initialize as NULL general Read/Only
rule
$Global:RwClients = @() # Reset R/W Clients
$Global:RoClients = @() # Reset R/O Clients
## VOLUME EXPORTS ##
$VolExportsOnly | Foreach {
If($Exports.$_.AnonSpecified){ [String]$Anon = ("-anon " +
$Exports.$_.AnonEquals) } else { [String]$Anon = $DefaultAnon }
If($Exports.$_.NoSuidSpecified){
[String]$Suid = ("-allow-suid false") } else { [String]$Suid =
$DefaultSuid }
If($Exports.$_.VolName -eq
$VolName){
$HasAVolOrSubVolExport =
Process-AllHosts $Exports.$_ # $VolName has a volume export (Process-AllHosts
always returns TRUE)
If($Exports.$_.RwSpecified){
$RwRule = ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys -rwrule
sys $Anon -superuser none $Suid $DefaultDev") }
If($Exports.$_.RoSpecified){
$RoRule = ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys -rwrule never
$Anon -superuser none $Suid $DefaultDev") }
}
}
## SUB VOLUME EXPORTS ##
$SubVolExportsOnly | Foreach {
If($Exports.$_.AnonSpecified){ [String]$Anon = ("-anon " +
$Exports.$_.AnonEquals) } else { [String]$Anon = $DefaultAnon }
If($Exports.$_.NoSuidSpecified){
[String]$Suid = ("-allow-suid false") } else { [String]$Suid =
$DefaultSuid }
If($Exports.$_.VolName -eq
$VolName){
$HasAVolOrSubVolExport =
Process-AllHosts $Exports.$_ # $VolName has a sub-volume export (Process-AllHosts
always returns TRUE)
If($Exports.$_.RwSpecified
-and !$RwRule){ $RwRule = ("$DefaultProtocol -clientmatch 0.0.0.0/0
-rorule sys -rwrule sys $Anon -superuser none $Suid $DefaultDev") }
If($Exports.$_.RoSpecified
-and !$RoRule){ $RoRule = ("$DefaultProtocol -clientmatch 0.0.0.0/0
-rorule sys -rwrule never $Anon -superuser none $Suid $DefaultDev") }
}
}
## IF THE VOLUME HAS AN EXPORTED QTREE,
ADD THE STANDARD READONLY RULE ##
If(
$cExports.Volume.$VolName.HasQtreeExports -and !$RwRule -and !$RoRule){ $RoRule
= ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys -rwrule never
$DefaultAnon -superuser none $DefaultSuid $DefaultDev") }
## IF WE HAVE A VOLUME OR SUB VOLUME
EXPORT, OUTPUT IT ##
If($HasAVolOrSubVolExport){
$RuleIndex = 1
$Output += ("vserver
export-policy create -vserver $VserverName -policyname $ExPolicy" )
$Global:RwRules | Foreach {
$Output += ($ExPolRuleStart + " " + [String]$RuleIndex + "
" + $_) ; $RuleIndex++ }
If($RwRule){ $Output +=
($ExPolRuleStart + " " + [String]$RuleIndex + " " +
$RwRule); $RuleIndex++ }
If(!$RwRule){
$Global:RoRules | Foreach {
[Boolean]$NotRwClient
= $TRUE
Foreach ($RwClient in
$Global:RwClients){ If($_ -match $RwClient){ $NotRwClient = $FALSE } }
If($NotRwClient){
$Output += ($ExPolRuleStart + " " + [String]$RuleIndex + "
" + $_); $RuleIndex++ }
}
}
If(!$RwRule -and $RoRule){ $Output
+= ($ExPolRuleStart + " " + [String]$RuleIndex + " " +
$RoRule); $RuleIndex++ }
$Output += ("volume modify
-vserver $VserverName -volume $VolName -policy $ExPolicy"),("")
}
}
##
CREATE AND APPLY PER QTREE EXPORT POLICIES (INCLUDES SUB-QTREE EXPORTS) ##
##
======================================================================= ##
$Output
+= ("## PER VOLUME QTREE POLICIES (INCLUDES SUB-QTREE EXPORTS
##"),("")
Foreach($VolName
in $cExports.ExportedVolList){ # Cycle through the Exported Volumes List
Foreach($QtreeName in
$cExports.Volume.$VolName.ExportedQtreeList){ # Cycle through the Exported
Qtrees for $VolName
[String]$ExPolicy = ("expol_q_" +
$VolName + "_" + $QtreeName.Replace(" ","_")) #
Qtree Names can have spaces in!
[String]$ExPolRuleStart = "vserver export-policy rule
create -vserver $VserverName -policyname $ExPolicy -ruleindex " # Add rule
indexes later
[Boolean]$HasAQtreeOrSubQtreeExport =
$FALSE # Initialize "Has a Qtree or Sub Qtree Export (for
$VolName.$QtreeName) as FALSE
$Global:RwRules = @() # Reset R/W Rules
$Global:RoRules = @() # Reset R/O Rules
[String]$RwRule = "" # Initialize as NULL general Read/Write
rule
[String]$RoRule = "" # Initialize as NULL general Read/Only
rule
$Global:RwClients = @() # Reset R/W Clients
$Global:RoClients = @() # Reset R/O Clients
## QTREE EXPORTS ##
$QtreeExportsOnly | Foreach {
If($Exports.$_.AnonSpecified){ [String]$Anon = ("-anon " + $Exports.$_.AnonEquals)
} else { [String]$Anon = $DefaultAnon }
If($Exports.$_.NoSuidSpecified){
[String]$Suid = ("-allow-suid false") } else { [String]$Suid =
$DefaultSuid }
If($Exports.$_.VolName -eq $VolName){
If($Exports.$_.QtreeName -eq
$QtreeName){
$HasAQtreeOrSubQtreeExport =
Process-AllHosts $Exports.$_ # $QtreeName has a Qtree export (Process-AllHosts
always returns TRUE)
If($Exports.$_.RwSpecified){ $RwRule
= ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys -rwrule sys $Anon
-superuser none $Suid $DefaultDev") }
If($Exports.$_.RoSpecified){ $RoRule
= ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys -rwrule never
$Anon -superuser none $Suid $DefaultDev") }
}
}
}
## SUB QTREE EXPORTS ##
$SubQtreeExportsOnly | Foreach {
If($Exports.$_.AnonSpecified){ [String]$Anon = ("-anon " +
$Exports.$_.AnonEquals) } else { [String]$Anon = $DefaultAnon }
If($Exports.$_.NoSuidSpecified){
[String]$Suid = ("-allow-suid false") } else { [String]$Suid =
$DefaultSuid }
If($Exports.$_.VolName -eq $VolName){
If($Exports.$_.QtreeName -eq
$QtreeName){
$HasAQtreeOrSubQtreeExport =
Process-AllHosts $Exports.$_ # $QtreeName has a Sub-Qtree export
(Process-AllHosts always returns TRUE)
If($Exports.$_.RwSpecified -and
!$RwRule){ $RwRule = ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys
-rwrule sys $Anon -superuser none $Suid $DefaultDev") }
If($Exports.$_.RoSpecified -and
!$RoRule){ $RoRule = ("$DefaultProtocol -clientmatch 0.0.0.0/0 -rorule sys
-rwrule never $Anon -superuser none $Suid $DefaultDev") }
}
}
}
## IF WE HAVE A QTREE OR SUB QTREE EXPORT,
OUTPUT IT ##
If($HasAQtreeOrSubQtreeExport){
$RuleIndex = 1
$Output += ("vserver export-policy
create -vserver $VserverName -policyname $ExPolicy" )
$Global:RwRules | Foreach { $Output +=
($ExPolRuleStart + " " + [String]$RuleIndex + " " + $_);
$RuleIndex++ }
If($RwRule){ $Output += ($ExPolRuleStart
+ " " + [String]$RuleIndex + " " + $RwRule); $RuleIndex++ }
If(!$RwRule){ $Global:RoRules | Foreach {
$Output += ($ExPolRuleStart + " " + [String]$RuleIndex + "
" + $_); $RuleIndex++ } }
If(!$RwRule -and $RoRule){ $Output +=
($ExPolRuleStart + " " + [String]$RuleIndex + " " +
$RoRule); $RuleIndex++ }
$Output += ("qtree modify -vserver
$VserverName -volume $VolName -qtree " + '"' + $QtreeName + '"'
+ " -export-policy $ExPolicy"),("")
}
}
}
##################################
##
CLUSTERSHELL COMMANDS OUTPUT ##
##################################
Wr
">>> STEP 3: CLUSTERSHELL COMMANDS OUTPUT <<<"
MAGENTA; Wr; Wr
Wr
("For Clustershell commands see text file: " + ($FileName +
"-CONVERTED_TO_CSHELL.txt")); Wr
Wr
("For log of screen output see: " + ($FileName +
"-7toC_SCREEN_OUTPUT")); Wr; Wr
$Output
| Out-File ($FileName + "-CONVERTED_TO_CSHELL.txt")
$Global:SOut
| Out-File ($FileName + "-7toC_SCREEN_OUTPUT.txt")
NotePad
($FileName + "-CONVERTED_TO_CSHELL.txt")
Comments
Post a Comment