Introduction
If you want to manually convert your 7-Mode exports file
into the equivalent Clustered Data ONTAP Export Polices and Export Policy Rules
- as close to equivalent as reasonably possible anyway - the following
PowerShell script might help you to do this.
It only handles -sec=sys
exports (which is probably 99.9% of exports anyway).
It doesn’t handle -actual=
which isn’t supported in cDOT (check out NetApp TR-4067.)
Because you can only export at the volume level or qtree
level in cDOT (8.2.1+), the tool consolidates volume and sub-volume (without a
Qtree in the path) exports into volume specific Export Policies, and
qtree and sub-qtree exports into qtree specific Export Policies.
The r/o hosts and r/w hosts need to be split out into
separate rules. The r/o rules are always placed after the r/w rules.
The script is easy to run. Name it as say 7CET.ps1, and
run as:
.\7CET.ps1
-FilePath YOUR_7M_EXPORTS_FILE
N.B. 7CET = 7 to C Exports Transitioner
The Script
(formatted for blogger)
############################################
##
7 to C Exports Transitioner (7CET.ps1) ##
############################################
Param(
# 7-Mode Exports File
[Parameter(Mandatory=$true)][String]$FilePath,
# cDOT: Vserver Name
[String]$VserverName = "SVM1",
# Specify a list as -
"vol1.folder1","vol2.folder2",...
# ... where ??? in the path /vol/VOLNAME/???
is not a Qtree
[System.Array]$OverrideQtrees
)
#
We use the FileName in some outputs
[String]$FileName
= $FilePath.Split("\")[0]
#
Records lines of Screen Output (flushed to SOut on Wr)
[String]$Global:LOut
= ""
#
Used to record the ScreenOutput
[System.Array]$Global:SOut
= @()
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.0 >>>>>"
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
}
}
# RETURN THE PROCESSED ARRAY
, $ProcessedArray
}
$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 #####
# Expect (1)PATH_BIT[0]/(2)OPTIONS_BIT[1]
[System.Array]$SplitOnDashSec =
$Line.Replace("-sec=","#").Split("#")
[System.Array]$SplitOnDashActual =
$Line.Replace("-actual=","#").Split("#")
If( !( ($SplitOnDashSec.Count -eq 2) -or
($SplitOnDashActual.Count -eq 2) ) ){
# NOT A VALID LINE ( .LineIsValid remains
FALSE)
RETURN
}
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")
}
# Expect
(1)[0]/(2)vol[1]/(3)VOLNAME[2]/(4){QTREE}[3]/{SUBQTREE_BIT}
$SplitOnSlash = $PathBit.Split("/")
If($SplitOnSlash.Count -lt 3){
# NOT A VALID LINE ( .LineIsValid remains
FALSE)
RETURN
}
[String]$VolNameFromExport = $SplitOnSlash[2]
$Exports.$Index.VolName = $VolNameFromExport
If($SplitOnSlash.Count -ge 4){
$PossibleQtree =
$SplitOnSlash[3].Replace("\"," ")
# N.B. 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("\"," ")
# N.B. 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(",")
# N.B. 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
$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 ##
# DATA STRUCTURE TO CONTAIN 7-MODE EXPORTS
[System.Object]$Exports.$Index = @{}
# /vol/VOLNAME
[String]$Exports.$Index.VolName =
""
# /vol/VOLNAME/QTREENAME
[String]$Exports.$Index.QtreeName =
""
# /vol/VOLNAME/QTREENAME/SUBQTREEBIT
[String]$Exports.$Index.SubQtreeBit =
""
# actual= is specified
[Boolean]$Exports.$Index.ActualSpecified =
$FALSE
# actual={path}
[String]$Exports.$Index.ActualEquals =
""
# anon= is specified
[Boolean]$Exports.$Index.AnonSpecified =
$FALSE
# anon={uid|name}
[String]$Exports.$Index.AnonEquals =
""
# nosuid is specified
[Boolean]$Exports.$Index.NoSuidSpecified = $FALSE
# ro is specified (with no equals)
[Boolean]$Exports.$Index.RoSpecified = $FALSE
# ro={clientid[:clientid...]}
[String]$Exports.$Index.RoEquals =
""
# rw is specified (with no equals)
[Boolean]$Exports.$Index.RwSpecified = $FALSE
# rw={clientid[:clientid...]}
[String]$Exports.$Index.RwEquals =
""
# root={clientid[:clientid...]}
[String]$Exports.$Index.RootEquals =
""
# sec={sectype[:sectype...]}
[String]$Exports.$Index.SecEquals =
""
# (... check exports line is valid ...)
[Boolean]$Exports.$Index.LineIsValid = $FALSE
# (... record the line sent for processing
...)
[String]$Exports.$Index.OriginalLine =
""
# 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 ##
##
============================= ##
#
Array for volume exports only - /vol/VOLNAME
[System.Array]$VolExportsOnly
= @()
#
Array for sub-volume exports only - /vol/VOLNAME/SUB-FOLDER
[System.Array]$SubVolExportsOnly
= @()
#
Array for qtree exports only - /vol/VOLNAME/QTREENAME
[System.Array]$QtreeExportsOnly
= @()
#
Array for sub-qtree exports only - /vol/VOLNAME/QTREENAME/SUB-QTREE-FOLDER
[System.Array]$SubQtreeExportsOnly
= @()
#
Initialize cExports object
[System.Object]$cExports
= @{}
#
Create an array for the ExportedVolumeList
[System.Array]$cExports.ExportedVolList
= @()
#
Create an object for volumes
[System.Object]$cExports.Volume
= @{}
##
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){
# 7M Exports that have NO Qtree NOR a
Sub-Qtree bit
$VolExportsOnly += $i
} elseif (!$QtreeName -and $Exports.$i.SubQtreeBit){
# 7M Exports that have NO Qtree BUT a
Sub-Qtree (Sub-Volume) bit
$SubVolExportsOnly += $i
}
elseif ($QtreeName -and
!$Exports.$i.SubQtreeBit){
# 7M Exports that have a Qtree and NO
Sub-Qtree bit
$QtreeExportsOnly += $i
}
elseif ($QtreeName -and $Exports.$i.SubQtreeBit){
# 7M Exports that have a Qtree and a
Sub-Qtree bit
$SubQtreeExportsOnly += $i
}
## 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) ){
# Accumulate the Exported Vols List
$cExports.ExportedVolList += $VolName
# Create an object for this volume
[System.Object]$cExports.Volume.$VolName
= @{}
# Initialize as FALSE for has Qtree
Exports
[Boolean]$cExports.Volume.$VolName.HasQtreeExports = $FALSE
# Create an array for exported qtrees
for $VolName
[System.Array]$cExports.Volume.$VolName.ExportedQtreeList = @()
}
## 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
##"),("")
#
Mount Volumes
$cExports.ExportedVolList
| Foreach {
$Output += ("volume mount -vserver
$VserverName -junction-path /vol/$_")
}
$Output
+= (""),("## CREATE NO ACCESS AND READONLY EXPORT POLICIES
(8.2+) ##"),("")
#
No Access Export Policy
$Output
+= ("vserver export-policy create -vserver $VserverName -policyname
expol_noaccess")
#
Read Only Export Policy
$Output
+= ("vserver export-policy create -vserver $VserverName -policyname
expol_readonly")
$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
##"),("")
#
Initially apply readonly to all volumes
$cExports.ExportedVolList
| Foreach {
$Output += "volume modify -vserver
$VserverName -volume $_ -policy expol_readonly"
}
$Output
+= (""),("## INITIALLY APPLY NO ACCESS TO QTREES ON EXPORTED
VOLUMES ##"),("")
#
Initially apply no access to all qtrees
$cExports.ExportedVolList
| Foreach {
$Output += ("qtree modify -vserver
$VserverName -volume $_ -qtree !" + '"' + '"' + "
-export-policy expol_noaccess")
}
$Output
+= ("")
##
FUNCTION TO PROCESS ROOT HOSTS, RW HOSTS, AND RO HOSTS ##
##
====================================================== ##
#
Initialize array for Read/Write Rules (must come before ro rules)
[System.Array]$Global:RwRules = @()
#
Initialize array for Read/Only Rules
[System.Array]$Global:RoRules = @()
#
Initialize array for RW Clients (used to prevent duplicates)
[System.Array]$Global:RwClients
= @()
#
Initialize array for RO Clients (used to prevent duplicates)
[System.Array]$Global:RoClients
= @()
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){
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){
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){
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) ##
##
========================================================================= ##
#
Not specified in 7-Mode
[String]$DefaultProtocol
= "-protocol any"
#
Same default in 7-Mode (so, if not specified is this)
[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"
$Output
+= ("## PER VOLUME EXPORT POLICIES (INCLUDES SUB-VOLUME EXPORTS
##"),("")
###
CYCLE THROUGH THE EXPORTED VOLUMES LIST ##
Foreach($VolName
in $cExports.ExportedVolList){
[String]$ExPolicy = ("expol_v_" +
$VolName)
# N.B. We add rule indexes later
[String]$ExPolRuleStart = "vserver
export-policy rule create -vserver $VserverName -policyname $ExPolicy
-ruleindex "
# Initialize "Has a Vol or Sub Vol
Export (for $VolName) as FALSE
[Boolean]$HasAVolOrSubVolExport = $FALSE
# Reset R/W Rules
$Global:RwRules = @()
# Reset R/O Rules
$Global:RoRules = @()
# Initialize as NULL general Read/Write rule
[String]$RwRule = ""
# Initialize as NULL general Read/Only rule
[String]$RoRule = ""
# Reset R/W Clients
$Global:RwClients = @()
# Reset R/O Clients
$Global:RoClients = @()
## 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){
# $VolName has a volume export
(Process-AllHosts always returns TRUE)
$HasAVolOrSubVolExport = Process-AllHosts
$Exports.$_
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){
# $VolName has a sub-volume export
(Process-AllHosts always returns TRUE)
$HasAVolOrSubVolExport = Process-AllHosts
$Exports.$_
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
##"),("")
##
CYCLE THROUGH THE EXPORTED VOLUMES LIST ##
Foreach($VolName
in $cExports.ExportedVolList){
## CYCLE THROUGH THE EXPORTED QTREES FOR
$VOLNAME ##
Foreach($QtreeName in
$cExports.Volume.$VolName.ExportedQtreeList){
# Qtree Names can have spaces in!
[String]$ExPolicy = ("expol_q_" +
$VolName + "_" + $QtreeName.Replace(" ","_"))
# Add rule indexes later
[String]$ExPolRuleStart = "vserver
export-policy rule create -vserver $VserverName -policyname $ExPolicy
-ruleindex "
# Initialize "Has a Qtree or Sub Qtree
Export (for $VolName.$QtreeName) as FALSE
[Boolean]$HasAQtreeOrSubQtreeExport =
$FALSE
# Reset R/W Rules
$Global:RwRules = @()
# Reset R/O Rules
$Global:RoRules = @()
# Initialize as NULL general Read/Write
rule
[String]$RwRule = ""
# Initialize as NULL general Read/Only rule
[String]$RoRule = ""
# Reset R/W Clients
$Global:RwClients = @()
# Reset R/O Clients
$Global:RoClients = @()
## 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){
# $QtreeName has a Qtree export
(Process-AllHosts always returns TRUE)
$HasAQtreeOrSubQtreeExport =
Process-AllHosts $Exports.$_
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){
# $QtreeName has a Sub-Qtree export
(Process-AllHosts always returns TRUE)
$HasAQtreeOrSubQtreeExport =
Process-AllHosts $Exports.$_
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")
Great script, tiny bug:
ReplyDeletevserver export-policy rule create -vservername
needs to be replaced by
vserver export-policy rule create -vserver
Hi Unknown, thank you for pointing out the error, I've updated the post to replace -vservername with -vserver. I do have an updated version v1.1, I'm pretty sure the only change was a fix for discovering incorrect subnets in the 7-Mode exports file. Let me know if you want me to post the update. Cheers VC
Delete