Skip to content

Commit 9a3101f

Browse files
committed
docs: add array-replication workflow example
Bidirectional FlashBlade-to-FlashBlade connection with: - Certificate groups + member trust bundles on both arrays - Connection key exchange (B generates, A connects) - Active side (POST) + passive side (adopt via GET+PATCH) - Replication address configuration on both ends
1 parent e980524 commit 9a3101f

2 files changed

Lines changed: 242 additions & 0 deletions

File tree

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# =============================================================================
2+
# Array Replication — Bidirectional FlashBlade-to-FlashBlade Connection
3+
# =============================================================================
4+
#
5+
# Complete workflow for establishing encrypted replication between two
6+
# FlashBlade arrays, including certificate trust, key exchange, and
7+
# replication address configuration on both sides.
8+
#
9+
# Architecture:
10+
#
11+
# [FlashBlade A (initiator)] [FlashBlade B (passive)]
12+
# | |
13+
# [Certificate Group] [Certificate Group]
14+
# |-- [Self-signed cert member] |-- [Self-signed cert member]
15+
# |-- [Custom cert member] |-- [Custom cert member]
16+
# | |
17+
# | connection_key ←────── [Connection Key generated on B]
18+
# | |
19+
# [Array Connection] ──── encrypted ────> [Array Connection (auto-created)]
20+
# replication_addresses: [A-data-vip] replication_addresses: [B-data-vip]
21+
#
22+
# Flow:
23+
# 1. Create certificate groups on both arrays (trust bundles)
24+
# 2. Add self-signed + custom certificates to each group
25+
# 3. Generate a connection key on array B
26+
# 4. Array A initiates the connection using B's key + management address
27+
# 5. Array B adopts the auto-created passive connection and sets replication addresses
28+
#
29+
# Prerequisites:
30+
# - Two FlashBlade arrays with REST API v2.22+ (Purity//FB 4.6.7+)
31+
# - Network connectivity between management and data VIPs
32+
# - Self-signed certificates already present on each array
33+
#
34+
# Usage:
35+
# 1. Copy terraform.tfvars.example to terraform.tfvars
36+
# 2. Fill in endpoints, API tokens, and network addresses
37+
# 3. terraform init && terraform apply
38+
#
39+
# =============================================================================
40+
41+
terraform {
42+
required_providers {
43+
flashblade = {
44+
source = "numberly/flashblade"
45+
}
46+
}
47+
}
48+
49+
# --- Variables ---------------------------------------------------------------
50+
51+
variable "array_a_endpoint" {
52+
description = "Management endpoint of FlashBlade A (initiator)."
53+
type = string
54+
}
55+
56+
variable "array_a_api_token" {
57+
description = "API token for FlashBlade A."
58+
type = string
59+
sensitive = true
60+
}
61+
62+
variable "array_b_endpoint" {
63+
description = "Management endpoint of FlashBlade B (passive)."
64+
type = string
65+
}
66+
67+
variable "array_b_api_token" {
68+
description = "API token for FlashBlade B."
69+
type = string
70+
sensitive = true
71+
}
72+
73+
variable "array_a_name" {
74+
description = "Name of FlashBlade A as it appears in the other array's connection list."
75+
type = string
76+
}
77+
78+
variable "array_b_name" {
79+
description = "Name of FlashBlade B as it appears in the other array's connection list."
80+
type = string
81+
}
82+
83+
variable "array_a_management_address" {
84+
description = "Management IP or FQDN of FlashBlade A (used by B to connect)."
85+
type = string
86+
}
87+
88+
variable "array_b_management_address" {
89+
description = "Management IP or FQDN of FlashBlade B (used by A to connect)."
90+
type = string
91+
}
92+
93+
variable "array_a_replication_address" {
94+
description = "Data VIP of FlashBlade A for replication traffic."
95+
type = string
96+
}
97+
98+
variable "array_b_replication_address" {
99+
description = "Data VIP of FlashBlade B for replication traffic."
100+
type = string
101+
}
102+
103+
variable "array_a_cert_name" {
104+
description = "Name of the self-signed certificate on FlashBlade A."
105+
type = string
106+
}
107+
108+
variable "array_b_cert_name" {
109+
description = "Name of the self-signed certificate on FlashBlade B."
110+
type = string
111+
}
112+
113+
variable "custom_cert_name" {
114+
description = "Name of a custom certificate present on both arrays (e.g. imported via flashblade_certificate)."
115+
type = string
116+
default = ""
117+
}
118+
119+
variable "encrypted" {
120+
description = "Whether replication traffic is encrypted."
121+
type = bool
122+
default = true
123+
}
124+
125+
# --- Providers ---------------------------------------------------------------
126+
127+
provider "flashblade" {
128+
alias = "array_a"
129+
endpoint = var.array_a_endpoint
130+
api_token = var.array_a_api_token
131+
}
132+
133+
provider "flashblade" {
134+
alias = "array_b"
135+
endpoint = var.array_b_endpoint
136+
api_token = var.array_b_api_token
137+
}
138+
139+
# --- Step 1: Certificate Groups (trust bundles) ------------------------------
140+
141+
resource "flashblade_certificate_group" "array_a" {
142+
provider = flashblade.array_a
143+
name = "_default_replication_certs"
144+
}
145+
146+
resource "flashblade_certificate_group" "array_b" {
147+
provider = flashblade.array_b
148+
name = "_default_replication_certs"
149+
}
150+
151+
# --- Step 2: Add certificates to groups -------------------------------------
152+
153+
# Each array's self-signed certificate
154+
resource "flashblade_certificate_group_member" "array_a_self" {
155+
provider = flashblade.array_a
156+
group_name = flashblade_certificate_group.array_a.name
157+
certificate_name = var.array_a_cert_name
158+
}
159+
160+
resource "flashblade_certificate_group_member" "array_b_self" {
161+
provider = flashblade.array_b
162+
group_name = flashblade_certificate_group.array_b.name
163+
certificate_name = var.array_b_cert_name
164+
}
165+
166+
# Custom certificate (optional — e.g. imported via flashblade_certificate)
167+
resource "flashblade_certificate_group_member" "array_a_custom" {
168+
count = var.custom_cert_name != "" ? 1 : 0
169+
provider = flashblade.array_a
170+
group_name = flashblade_certificate_group.array_a.name
171+
certificate_name = var.custom_cert_name
172+
}
173+
174+
resource "flashblade_certificate_group_member" "array_b_custom" {
175+
count = var.custom_cert_name != "" ? 1 : 0
176+
provider = flashblade.array_b
177+
group_name = flashblade_certificate_group.array_b.name
178+
certificate_name = var.custom_cert_name
179+
}
180+
181+
# --- Step 3: Generate connection key on array B ------------------------------
182+
183+
resource "flashblade_array_connection_key" "array_b" {
184+
provider = flashblade.array_b
185+
}
186+
187+
# --- Step 4: Array A initiates connection to B (active side) -----------------
188+
189+
resource "flashblade_array_connection" "a_to_b" {
190+
provider = flashblade.array_a
191+
remote_name = var.array_b_name
192+
management_address = var.array_b_management_address
193+
connection_key = flashblade_array_connection_key.array_b.connection_key
194+
encrypted = var.encrypted
195+
196+
replication_addresses = [var.array_a_replication_address]
197+
}
198+
199+
# --- Step 5: Array B adopts passive connection and sets replication address --
200+
201+
resource "flashblade_array_connection" "b_to_a" {
202+
provider = flashblade.array_b
203+
remote_name = var.array_a_name
204+
encrypted = var.encrypted
205+
replication_addresses = [var.array_b_replication_address]
206+
207+
# Wait for A to connect first — B's passive connection is auto-created by FlashBlade.
208+
depends_on = [flashblade_array_connection.a_to_b]
209+
}
210+
211+
# --- Outputs -----------------------------------------------------------------
212+
213+
output "connection_a_to_b_status" {
214+
description = "Status of the connection from array A to array B."
215+
value = flashblade_array_connection.a_to_b.status
216+
}
217+
218+
output "connection_b_to_a_status" {
219+
description = "Status of the connection from array B to array A."
220+
value = flashblade_array_connection.b_to_a.status
221+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# FlashBlade A (initiator)
2+
array_a_endpoint = "https://fb-dc1.example.com"
3+
array_a_api_token = "T-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
4+
array_a_name = "fb-dc1"
5+
array_a_management_address = "10.1.0.1"
6+
array_a_replication_address = "10.1.1.1"
7+
array_a_cert_name = "fb-dc1"
8+
9+
# FlashBlade B (passive)
10+
array_b_endpoint = "https://fb-dc2.example.com"
11+
array_b_api_token = "T-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
12+
array_b_name = "fb-dc2"
13+
array_b_management_address = "10.2.0.1"
14+
array_b_replication_address = "10.2.1.1"
15+
array_b_cert_name = "fb-dc2"
16+
17+
# Optional: custom certificate present on both arrays
18+
# custom_cert_name = "wildcard-replication-cert"
19+
20+
# Encryption (default: true)
21+
# encrypted = true

0 commit comments

Comments
 (0)