Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 86293f9

Browse filesBrowse files
authored
samples: add default leader options samples (googleapis#428)
* feat: add configurable leader placement support * lint * Create multi-regional instances * try another print stmt * try nam3 * variable for config * samples: add default leader options samples * fix * fix * fix * use sample instance * use new default leader instance * fix * underscore rather than dashes? * fix * add reload * review changes
1 parent 8de7856 commit 86293f9
Copy full SHA for 86293f9

File tree

Expand file treeCollapse file tree

3 files changed

+266
-0
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+266
-0
lines changed

‎samples/samples/conftest.py

Copy file name to clipboardExpand all lines: samples/samples/conftest.py
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,26 @@ def instance_id():
7474
return f"test-instance-{uuid.uuid4().hex[:10]}"
7575

7676

77+
@pytest.fixture(scope="module")
78+
def multi_region_instance_id():
79+
"""Unique id for the multi-region instance used in samples."""
80+
return f"multi-instance-{uuid.uuid4().hex[:10]}"
81+
82+
7783
@pytest.fixture(scope="module")
7884
def instance_config(spanner_client):
7985
return "{}/instanceConfigs/{}".format(
8086
spanner_client.project_name, "regional-us-central1"
8187
)
8288

8389

90+
@pytest.fixture(scope="module")
91+
def multi_region_instance_config(spanner_client):
92+
return "{}/instanceConfigs/{}".format(
93+
spanner_client.project_name, "nam3"
94+
)
95+
96+
8497
@pytest.fixture(scope="module")
8598
def sample_instance(
8699
spanner_client, cleanup_old_instances, instance_id, instance_config, sample_name,
@@ -113,6 +126,42 @@ def sample_instance(
113126
sample_instance.delete()
114127

115128

129+
@pytest.fixture(scope="module")
130+
def multi_region_instance(
131+
spanner_client,
132+
cleanup_old_instances,
133+
multi_region_instance_id,
134+
multi_region_instance_config,
135+
sample_name,
136+
):
137+
multi_region_instance = spanner_client.instance(
138+
multi_region_instance_id,
139+
multi_region_instance_config,
140+
labels={
141+
"cloud_spanner_samples": "true",
142+
"sample_name": sample_name,
143+
"created": str(int(time.time()))
144+
},
145+
)
146+
retry_429 = retry.RetryErrors(exceptions.ResourceExhausted, delay=15)
147+
op = retry_429(multi_region_instance.create)()
148+
op.result(120) # block until completion
149+
150+
# Eventual consistency check
151+
retry_found = retry.RetryResult(bool)
152+
retry_found(multi_region_instance.exists)()
153+
154+
yield multi_region_instance
155+
156+
for database_pb in multi_region_instance.list_databases():
157+
database.Database.from_pb(database_pb, multi_region_instance).drop()
158+
159+
for backup_pb in multi_region_instance.list_backups():
160+
backup.Backup.from_pb(backup_pb, multi_region_instance).delete()
161+
162+
multi_region_instance.delete()
163+
164+
116165
@pytest.fixture(scope="module")
117166
def database_id():
118167
"""Id for the database used in samples.

‎samples/samples/snippets.py

Copy file name to clipboardExpand all lines: samples/samples/snippets.py
+153Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,53 @@ def create_instance_with_processing_units(instance_id, processing_units):
9696
# [END spanner_create_instance_with_processing_units]
9797

9898

99+
# [START spanner_get_instance_config]
100+
def get_instance_config(instance_config):
101+
"""Gets the leader options for the instance configuration."""
102+
spanner_client = spanner.Client()
103+
config_name = "{}/instanceConfigs/{}".format(spanner_client.project_name, instance_config)
104+
config = spanner_client.instance_admin_api.get_instance_config(name=config_name)
105+
print("Available leader options for instance config {}: {}".format(
106+
instance_config, config.leader_options))
107+
108+
109+
# [END spanner_get_instance_config]
110+
111+
112+
# [START spanner_list_instance_configs]
113+
def list_instance_config():
114+
"""Lists the available instance configurations."""
115+
spanner_client = spanner.Client()
116+
configs = spanner_client.list_instance_configs()
117+
for config in configs:
118+
print(
119+
"Available leader options for instance config {}: {}".format(
120+
config.name, config.leader_options
121+
)
122+
)
123+
124+
125+
# [END spanner_list_instance_configs]
126+
127+
128+
# [START spanner_list_databases]
129+
def list_databases(instance_id):
130+
"""Lists databases and their leader options."""
131+
spanner_client = spanner.Client()
132+
instance = spanner_client.instance(instance_id)
133+
134+
databases = list(instance.list_databases())
135+
for database in databases:
136+
print(
137+
"Database {} has default leader {}".format(
138+
database.name, database.default_leader
139+
)
140+
)
141+
142+
143+
# [END spanner_list_databases]
144+
145+
99146
# [START spanner_create_database]
100147
def create_database(instance_id, database_id):
101148
"""Creates a database and tables for sample data."""
@@ -168,6 +215,112 @@ def create_database_with_encryption_key(instance_id, database_id, kms_key_name):
168215
# [END spanner_create_database_with_encryption_key]
169216

170217

218+
# [START spanner_create_database_with_default_leader]
219+
def create_database_with_default_leader(
220+
instance_id, database_id, default_leader
221+
):
222+
"""Creates a database with tables with a default leader."""
223+
spanner_client = spanner.Client()
224+
instance = spanner_client.instance(instance_id)
225+
226+
database = instance.database(
227+
database_id,
228+
ddl_statements=[
229+
"""CREATE TABLE Singers (
230+
SingerId INT64 NOT NULL,
231+
FirstName STRING(1024),
232+
LastName STRING(1024),
233+
SingerInfo BYTES(MAX)
234+
) PRIMARY KEY (SingerId)""",
235+
"""CREATE TABLE Albums (
236+
SingerId INT64 NOT NULL,
237+
AlbumId INT64 NOT NULL,
238+
AlbumTitle STRING(MAX)
239+
) PRIMARY KEY (SingerId, AlbumId),
240+
INTERLEAVE IN PARENT Singers ON DELETE CASCADE""",
241+
"ALTER DATABASE {}"
242+
" SET OPTIONS (default_leader = '{}')".format(database_id, default_leader),
243+
],
244+
)
245+
operation = database.create()
246+
247+
print("Waiting for operation to complete...")
248+
operation.result(120)
249+
250+
database.reload()
251+
252+
print(
253+
"Database {} created with default leader {}".format(
254+
database.name, database.default_leader
255+
)
256+
)
257+
258+
259+
# [END spanner_create_database_with_default_leader]
260+
261+
262+
# [START spanner_update_database_with_default_leader]
263+
def update_database_with_default_leader(
264+
instance_id, database_id, default_leader
265+
):
266+
"""Updates a database with tables with a default leader."""
267+
spanner_client = spanner.Client()
268+
instance = spanner_client.instance(instance_id)
269+
270+
database = instance.database(database_id)
271+
272+
operation = database.update_ddl(["ALTER DATABASE {}"
273+
" SET OPTIONS (default_leader = '{}')".format(database_id, default_leader)])
274+
operation.result(120)
275+
276+
database.reload()
277+
278+
print(
279+
"Database {} updated with default leader {}".format(
280+
database.name, database.default_leader
281+
)
282+
)
283+
284+
285+
# [END spanner_update_database_with_default_leader]
286+
287+
288+
# [START spanner_get_database_ddl]
289+
def get_database_ddl(instance_id, database_id):
290+
"""Gets the database DDL statements."""
291+
spanner_client = spanner.Client()
292+
instance = spanner_client.instance(instance_id)
293+
database = instance.database(database_id)
294+
ddl = spanner_client.database_admin_api.get_database_ddl(database=database.name)
295+
print("Retrieved database DDL for {}".format(database_id))
296+
for statement in ddl.statements:
297+
print(statement)
298+
299+
300+
# [END spanner_get_database_ddl]
301+
302+
303+
# [START spanner_query_information_schema_database_options]
304+
def query_information_schema_database_options(instance_id, database_id):
305+
"""Queries the default leader of a database."""
306+
spanner_client = spanner.Client()
307+
instance = spanner_client.instance(instance_id)
308+
database = instance.database(database_id)
309+
with database.snapshot() as snapshot:
310+
results = snapshot.execute_sql(
311+
"SELECT OPTION_VALUE AS default_leader "
312+
"FROM INFORMATION_SCHEMA.DATABASE_OPTIONS "
313+
"WHERE SCHEMA_NAME = '' AND OPTION_NAME = 'default_leader'"
314+
)
315+
for result in results:
316+
print("Database {} has default leader {}".format(
317+
database_id, result[0]
318+
))
319+
320+
321+
# [END spanner_query_information_schema_database_options]
322+
323+
171324
# [START spanner_insert_data]
172325
def insert_data(instance_id, database_id):
173326
"""Inserts sample data into the given database.

‎samples/samples/snippets_test.py

Copy file name to clipboardExpand all lines: samples/samples/snippets_test.py
+64Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ def cmek_database_id():
7373
return f"cmek-db-{uuid.uuid4().hex[:10]}"
7474

7575

76+
@pytest.fixture(scope="module")
77+
def default_leader_database_id():
78+
return f"leader_db_{uuid.uuid4().hex[:10]}"
79+
80+
7681
@pytest.fixture(scope="module")
7782
def database_ddl():
7883
"""Sequence of DDL statements used to set up the database.
@@ -82,6 +87,12 @@ def database_ddl():
8287
return [CREATE_TABLE_SINGERS, CREATE_TABLE_ALBUMS]
8388

8489

90+
@pytest.fixture(scope="module")
91+
def default_leader():
92+
""" Default leader for multi-region instances. """
93+
return "us-east4"
94+
95+
8596
def test_create_instance_explicit(spanner_client, create_instance_id):
8697
# Rather than re-use 'sample_isntance', we create a new instance, to
8798
# ensure that the 'create_instance' snippet is tested.
@@ -119,6 +130,59 @@ def test_create_database_with_encryption_config(capsys, instance_id, cmek_databa
119130
assert kms_key_name in out
120131

121132

133+
def test_get_instance_config(capsys):
134+
instance_config = "nam6"
135+
snippets.get_instance_config(instance_config)
136+
out, _ = capsys.readouterr()
137+
assert instance_config in out
138+
139+
140+
def test_list_instance_config(capsys):
141+
snippets.list_instance_config()
142+
out, _ = capsys.readouterr()
143+
assert "regional-us-central1" in out
144+
145+
146+
def test_list_databases(capsys, instance_id):
147+
snippets.list_databases(instance_id)
148+
out, _ = capsys.readouterr()
149+
assert "has default leader" in out
150+
151+
152+
def test_create_database_with_default_leader(capsys, multi_region_instance, multi_region_instance_id, default_leader_database_id, default_leader):
153+
retry_429 = RetryErrors(exceptions.ResourceExhausted, delay=15)
154+
retry_429(snippets.create_database_with_default_leader)(
155+
multi_region_instance_id, default_leader_database_id, default_leader
156+
)
157+
out, _ = capsys.readouterr()
158+
assert default_leader_database_id in out
159+
assert default_leader in out
160+
161+
162+
def test_update_database_with_default_leader(capsys, multi_region_instance, multi_region_instance_id, default_leader_database_id, default_leader):
163+
retry_429 = RetryErrors(exceptions.ResourceExhausted, delay=15)
164+
retry_429(snippets.update_database_with_default_leader)(
165+
multi_region_instance_id, default_leader_database_id, default_leader
166+
)
167+
out, _ = capsys.readouterr()
168+
assert default_leader_database_id in out
169+
assert default_leader in out
170+
171+
172+
def test_get_database_ddl(capsys, instance_id, sample_database):
173+
snippets.get_database_ddl(instance_id, sample_database.database_id)
174+
out, _ = capsys.readouterr()
175+
assert sample_database.database_id in out
176+
177+
178+
def test_query_information_schema_database_options(capsys, multi_region_instance, multi_region_instance_id, default_leader_database_id, default_leader):
179+
snippets.query_information_schema_database_options(
180+
multi_region_instance_id, default_leader_database_id
181+
)
182+
out, _ = capsys.readouterr()
183+
assert default_leader in out
184+
185+
122186
@pytest.mark.dependency(name="insert_data")
123187
def test_insert_data(capsys, instance_id, sample_database):
124188
snippets.insert_data(instance_id, sample_database.database_id)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.