Skip to content

Commit 47165d9

Browse files
committed
Added the ability to read in the partnersTable from a DynamoDB.
1 parent e6c7f03 commit 47165d9

File tree

2 files changed

+96
-40
lines changed

2 files changed

+96
-40
lines changed

Management-Utilities/auto_create_sm_relationships/README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,35 @@ This script is used to ensure that all your volumes, in all your FSxN file syste
1515
## Set Up
1616
There are a few things you need to do in order to get this script to run properly:
1717

18-
- Set up a secret for each of the FSxN file systems in the AWS Secrets Manager. Each secret should have two "keys" (they can be named anything, since you set the key name in the script):
18+
- Set up a secret for each of the FSxN file systems in the AWS Secrets Manager. Each secret should have two "keys" (they can be named anything, since you set the name of the key the scretsTable defined below.):
1919
- username - set to the username you want the script to use when issuing API to the ONTAP system.
2020
- password - set to the password of the username specified with the username key.
2121
- Edit the top of the script and fill in a few variables:
2222
- partnerTable - This table provides the association with a source FSxN file system to its partner cluster (i.e. where its volumes should be SnapMirror'ed to.) There should be five fields for each entry:
2323
- fsxId - Set to the AWS ID of the FSx file system.
2424
- svmName - Set to the SVM name on the FSxN file system.
2525
- partnerFsxnIP - Set to the IP address of the management port of the partner FSxN file system.
26-
- partnerSvmName - The name of the SVM where you want the SnapMirror destination volume to resided.
26+
- partnerSvmName - The name of the SVM where you want the SnapMirror destination volume to reside.
2727
- partnerSvmSourceName - Is the "peered name" of the source SVM. Usually, it is the same as the source SVM, but can be different if that same name already exists on the partner file system. When you peer the SVM it will require you to create an alias for the source SVM so all the SVM names are unique.
28+
*NOTE:* Instead of defining the partnersTable in the script, you can define dynamodbPartnersTableName and dynamodbRegion and the script will read in the partner information from the specified DynamoDB table. The partners table should have the following fields:
29+
- soureceId - Which is the concatentation of the source file system ID followed by a ":" followed by the SVM name. It is done this way because the id has to be unique in the table. It is split up into its two components in the script when it is read in.
30+
- partnerFsxnIp - Set to the IP address of the management port of the partner FSxN file system.
31+
- partnerSvmName - The name of the SVM where you want the SnapMirror destination volume to reside.
32+
- partnerSvmSourceName - Is the "peered name" of the source SVM. Usually, it is the same as the source SVM, but can be different if that same name already exists on the partner file system. When you peer the SVM it will require you to create an alias for the source SVM so all the SVM names are unique.
33+
2834
- secretsTable - This table provides the secret name, and username and password keys to use for each of the file systems. It should have 4 fields:
29-
- id - Set to the AWS File System ID
35+
- fsxId - Set to the AWS File System ID
3036
- secretName - Set to the name of the secret created in step one.
31-
- usernameKey - Set to the name of the key that holds the username. In the instructions above, it should be set to 'username' but this allows you to use any key name you want.
37+
- usernameKey - Set to the name of the key that holds the username.
3238
- passwordKey - Set to the name of the key that holds the password.
33-
*NOTE:* Instead of defining the secretsTable in the script, you can define dynamodbTableName and dynamodbRegion and the script will read the secretsTable from the DynamoDB table. The table should have the same fields as the secretsTable.
39+
*NOTE:* Instead of defining the secretsTable in the script, you can define dynamodbSecretsTableName and dynamodbRegion and the script will read in the secretsTable information from the specified DynamoDB table. The table should have the same fields as the secretsTable defined above.
40+
3441
- secretsManagerRegion - Set to the region where the Secrets Manager has been set up.
3542
- destinationVolumeSuffix - Set to the string you want appended to the source volume name to create the destination volume name.
3643
- snapMirrorPolicy - Set to the Data ONTAP SnapMirror policy you want the assigned to the SnapMirror relationship.
37-
- maxSnapMirrorRelationships - Set to the maximum number of SnapMirror relationship initializations you want to allow running at the same time.
38-
- dryRun - If set to 'True' (case sensitive) the program will just show that it would have done, instead of actually creating the SnapMirror relationships.
44+
- maxSnapMirrorRelationships - Set to the maximum number of SnapMirror relationship initializations you want this script to create in a single run.
45+
- dryRun - If set to 'True' (case sensitive) the script will just show what it would have done, instead of actually creating the SnapMirror relationships.
46+
- protectAll - If set to 'True' (case sensitive) the script will protect all volumes that don't have a "protect_volume" tag set to "skip". If set to 'False' it will only protect volumes that have a "protect_volume" tag set to "protect".
3947

4048
If you want to run this script as a Lambda program, then you'll need to
4149
- Create a role that has the following permissions:
@@ -63,5 +71,5 @@ To run it as a Lambda function you will need to:
6371
- Create the Lambda function with a Python runtime, from scratch, and paste the program into code box and save it.
6472
- Associate the role created above with the Lambda function.
6573
- Create the AWS service endpoints mentioned above.
66-
- Adjust the default timeout from 4 seconds to at least 20, maybe 60 seconds.
74+
- Adjust the default timeout from 4 seconds to at least 60 seconds.
6775
- Once you have tested that it run successfully, creating an eventBridge that will trigger it to run on a regular basis (e.g. once or twice a day).

Management-Utilities/auto_create_sm_relationships/auto_create_sm_relationships.py

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,54 +29,82 @@
2929
################################################################################
3030
#
3131
# Create a table of source FSxN IDs and SVMs and its partner (destination)
32-
# cluster and SVM. The "partnerSvmSourceName" is the label for the source SVM at
33-
# the destination cluster. It is usually the same as the SVM name at the source,
32+
# cluster and SVM. How to fill in the table should be pretty obvious except
33+
# for the "partnerSvmSourceName". It is the label for the source SVM at the
34+
# destination cluster. Usually, the SVM name is the same as the source SVM name
3435
# unless there is a name conflict with SVM name at the destination, in which
3536
# case an "alias" is has to be created when you peer the SVMs (a.k.a. vservers).
36-
partnerTable = [
37+
# In this case partnerSvmSourceName should be set to that alias, otherwise
38+
# it should just be set the same as the svmName. It must be set though.
39+
#
40+
# You can either define an array named "partnersTable", like the one defined
41+
# below, or define dynamodbPartnersTableName that specifies a DynamoDB table
42+
# to scan to get the information. The DynamoDB table should have the
43+
# following attributes:
44+
# sourceId - Which is the concatentation of the source file system ID
45+
# followed by a ":" followed by the SVM name. It is done this
46+
# way because the id has to be unique in the table.
47+
# partnerFsxnIp - The IP address of the destination cluster.
48+
# partnerSvmName - The name of the SVM at the destination cluster.
49+
# partnerSvmSourceName - The name of the SVM at the destination cluster that
50+
# will be the source of the SnapMirror relationship.
51+
partnersTable = [
3752
{
3853
'fsxId': 'fs-0e8d9172XXXXXXXXX',
3954
'svmName': 'fsx',
40-
'partnerFsxnIp': '198.19.253.210',
55+
'partnerFsxnIp': '198.19.253.1',
4156
'partnerSvmName': 'fsx',
4257
'partnerSvmSourceName': 'fsx_source'
4358
},
4459
{
4560
'fsxId': 'fs-0e8d9172XXXXXXXXX',
4661
'svmName': 'fsx_smb',
47-
'partnerFsxnIp': '198.19.253.210',
62+
'partnerFsxnIp': '198.19.253.1',
4863
'partnerSvmName': 'fsx',
4964
'partnerSvmSourceName': 'fsx_smb'
5065
},
5166
{
5267
'fsxId': 'fs-020de268XXXXXXXXX',
5368
'svmName': 'fsx',
54-
'partnerFsxnIp': '198.19.255.162',
69+
'partnerFsxnIp': '198.19.255.1',
5570
'partnerSvmName': 'fsx',
5671
'partnerSvmSourceName': 'fsx_dest'
5772
},
5873
]
5974
#
75+
# If you don't want to define the partnersTable in this script, you can
76+
# define the following variables to use a DynamoDB table to get the
77+
# partner information.
78+
#
79+
# NOTE: If both the partnersTable and dynamodbPartnersTableName are defined,
80+
# the partnersTable will be used.
81+
#dynamodbRegion="us-west-2"
82+
#dynamodbPartnersTableName="fsx_partners"
83+
#
6084
# Create a table of secret names and keys for the username and password for each of the FSxIds.
6185
# You can either define an array named "secretsTable", like below or define
62-
# dynamodbTableName, that will specify a DynamoDB table to use. It should have the
86+
# dynamodbSecretsTableName, that will specify a DynamoDB table to use. It should have the
6387
# following attributes:
64-
# id - The file system ID
88+
# fsxId - The file system ID
6589
# SecretName - The name of the Amazon SecretManger secret that holds the username and password keys.
6690
# usernameKey - The name of the key that holds the username to use.
6791
# passwordKey - The name of the key that holds the password to use.
6892
#
69-
#secretsTable = [
70-
# {"id": "fs-0e8d9172XXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"},
71-
# {"id": "fs-020de268XXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"},
72-
# {"id": "fs-07bcb7adXXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"},
73-
# {"id": "fs-077b5ff4XXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"}
74-
# ]
93+
secretsTable = [
94+
{"fsxId": "fs-0e8d9172XXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"},
95+
{"fsxId": "fs-020de268XXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"},
96+
{"fsxId": "fs-07bcb7adXXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"},
97+
{"fsxId": "fs-077b5ff4XXXXXXXXX", "secretName": "fsxn-credentials", "usernameKey": "fsxn-username", "passwordKey": "fsxn-password"}
98+
]
7599
#
76-
# NOTE: If both the secretsTable, and dynamodbTableName are defined, the secretsTable will be used.
100+
# If you don't want to define the secretsTable in this script, you can
101+
# define the following variables to use a DynamoDB table to get the
102+
# secret information.
77103
#
78-
dynamodbTableName="fsxn_secrets"
79-
dynamodbRegion="us-west-2"
104+
# NOTE: If both the secretsTable, and dynamodbSecretsTableName are defined,
105+
# the secretsTable will be used.
106+
#dynamodbRegion="us-west-2"
107+
#dynamodbSecretsTableName="fsx_secrets"
80108
#
81109
# Provide the region the secrets manager resides in:
82110
secretsManagerRegion='us-west-2'
@@ -98,11 +126,11 @@
98126
# a signle run.
99127
maxSnapMirrorRelationships=10
100128
#
101-
# Set the following to 'True' (case sentitive) to have the program just
102-
# show what it would have done and not really peform any actions.
129+
# Set the following to 'True' (case sensitive) to have the program just
130+
# show what it would have done and not really perform any actions.
103131
dryRun=True
104132
#
105-
# Set the following to 'True' (case sentitive) to have the program protect
133+
# Set the following to 'True' (case sensitive) to have the program protect
106134
# all volumes that don't have a "protect_volume" tag set to "skip". Or, set
107135
# it to 'False' to only protect volumes that have a "protect_volume" tag
108136
# set to "protect".
@@ -171,7 +199,7 @@ def getCredentials(fsxnId):
171199
global secretsManagerClient, secretsTable
172200

173201
for secretItem in secretsTable:
174-
if secretItem['id'] == fsxnId:
202+
if secretItem['fsxId'] == fsxnId:
175203
secretsInfo = secretsManagerClient.get_secret_value(SecretId=secretItem['secretName'])
176204
secrets = json.loads(secretsInfo['SecretString'])
177205
username = secrets[secretItem['usernameKey']]
@@ -193,8 +221,8 @@ def protectFlexGroup(fsxId, svmName, volumeName):
193221

194222
################################################################################
195223
# This function is used to setup a snapmirror relationship for the source
196-
# volume passed in. It leverages the "create destionation endpoint"
197-
# capibilities of the snapmirror API which will create the destionation volume
224+
# volume passed in. It leverages the "create destination endpoint"
225+
# capabilities of the snapmirror API which will create the destination volume
198226
# with the same name as the source volume with a suffix appended to it.
199227
# The suffix is defined above.
200228
#
@@ -204,11 +232,11 @@ def protectFlexGroup(fsxId, svmName, volumeName):
204232
################################################################################
205233
def protectVolume(fsxId, svmName, volumeName):
206234

207-
global logger, http, numSnapMirrorRelationships, scheduleName
235+
global logger, http, numSnapMirrorRelationships, scheduleName, partnersTable
208236
#
209237
# find the partner cluster management IP and svm for the source fsxId and svm.
210238
partnerIp = ""
211-
for fsx in partnerTable:
239+
for fsx in partnersTable:
212240
if fsx['fsxId'] == fsxId and fsx['svmName'] == svmName:
213241
partnerIp = fsx['partnerFsxnIp']
214242
partnerSvmName = fsx['partnerSvmName']
@@ -235,7 +263,7 @@ def protectVolume(fsxId, svmName, volumeName):
235263
"state": "snapmirrored",
236264
"policy": snapMirrorPolicy}
237265
#
238-
# To be safe, check that the variable exist, since it migth have been
266+
# To be safe, check that the variable exist, since it might have been
239267
# commented out above.
240268
try:
241269
nop = scheduleName
@@ -300,7 +328,7 @@ def getOntapVolumes(fsxId, fsxnIp):
300328
def lambda_handler(event, context):
301329
#
302330
# Define some globals so we don't have to pass them around.
303-
global logger, http, secretsManagerClient, numSnapMirrorRelationships, secretsTable
331+
global logger, http, secretsManagerClient, numSnapMirrorRelationships, secretsTable, partnersTable
304332
#
305333
# Get a list of all the regions.
306334
ec2Client = boto3.client('ec2')
@@ -325,24 +353,44 @@ def lambda_handler(event, context):
325353
secretsManagerClient = session.client(service_name='secretsmanager', region_name=secretsManagerRegion)
326354
#
327355
# Read in the secretTable
356+
dynamodbClient = boto3.resource("dynamodb", region_name=dynamodbRegion)
328357
if 'secretsTable' not in globals():
329-
if 'dynamodbRegion' not in globals() or 'dynamodbTableName' not in globals():
330-
raise Exception('Error, you must either define the secretsTable array, or define dynamodbRegion and dynamodbTableName')
358+
if 'dynamodbRegion' not in globals() or 'dynamodbSecretsTableName' not in globals():
359+
raise Exception('Error, you must either define the secretsTable array at the top of this script, or define dynamodbRegion and dynamodbSecretsTableName')
331360

332-
dynamodbClient = boto3.resource("dynamodb", region_name=dynamodbRegion)
333-
table = dynamodbClient.Table(dynamodbTableName)
361+
table = dynamodbClient.Table(dynamodbSecretsTableName)
334362

335363
response = table.scan()
336364
secretsTable = response["Items"]
337365
#
366+
# Read in the partnersTable
367+
if 'partnersTable' not in globals():
368+
if 'dynamodbRegion' not in globals() or 'dynamodbPartnersTableName' not in globals():
369+
raise Exception('Error, you must either define the partnersTable array at the top of this script, or define dynamodbRegion and dynamodbPartnersTableName')
370+
371+
table = dynamodbClient.Table(dynamodbPartnersTableName)
372+
373+
response = table.scan()
374+
items = response["Items"]
375+
partnersTable = []
376+
for item in items:
377+
partner = {
378+
'fsxId': item['sourceId'].split(":")[0],
379+
'svmName': item['sourceId'].split(":")[1],
380+
'partnerFsxnIp': item['partnerFsxnIp'],
381+
'partnerSvmName': item['partnerSvmName'],
382+
'partnerSvmSourceName': item['partnerSvmSourceName']
383+
}
384+
partnersTable.append(partner)
385+
#
338386
# Disable warning about connecting to servers with self-signed SSL certificates.
339387
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
340388
#
341389
# Set the https retries to 1.
342390
retries = Retry(total=None, connect=1, read=1, redirect=10, status=0, other=0) # pylint: disable=E1123
343391
http = urllib3.PoolManager(cert_reqs='CERT_NONE', retries=retries)
344392
#
345-
# Create a counter of the number of SM reltionships created.
393+
# Create a counter of the number of SM relationships created.
346394
numSnapMirrorRelationships = 0
347395
#
348396
# Get the list of regions that support fsx.

0 commit comments

Comments
 (0)