Refactor and improve swift-rings.py

We can simplify and refactor swift_rings.py and swift_rings_check.py by
moving to a "FULL_HOST_KEY" model where we simply compare the full
string, rather than individual elements.

To do this we need to adjust the contents template to use the same field
values as used by swift:
* rename repl_ip to replication_ip
* rename repl_port to replication_port

Additionally, this allows us the ability to change port values on the
fly, by adjusting the "DEVICE_KEY" to only be the IP and device name the
port will now automatically get changed if the service port changes.

This is a precursor to adjusting the default swift storage service ports
to match upstream defaults, and will reduce the upgrade impact of that
task.

Change-Id: I704edcba4facb2170990ebec2a67d4179a023fc2
This commit is contained in:
Andy McCrae 2016-08-04 14:33:13 +01:00 committed by Steve Lewis (stevelle)
parent a7f0e1bd7c
commit 750ccaa9e8
5 changed files with 45 additions and 44 deletions

View File

@ -81,6 +81,11 @@ swift_middleware_list:
## Swift default ports ## Swift default ports
swift_proxy_port: "8080" swift_proxy_port: "8080"
# You can change the object, container, account ports.
# This will update the ring, on the next playbook run,
# without requiring a rebalance.
# NB: There is service downtime, during the run, between
# the service restart and the ring updating.
swift_object_port: "6000" swift_object_port: "6000"
swift_container_port: "6001" swift_container_port: "6001"
swift_account_port: "6002" swift_account_port: "6002"

View File

@ -0,0 +1,11 @@
---
features:
- Change the port for devices in the ring by adjusting
the port value for services, hosts, or devices. This
will not involve a rebalance of the ring.
- Changing the port for a device, or group of devices,
carries a brief period of downtime to the swift
storage services for those devices. The devices will
be unavailable during period between when the
storage service restarts after the port update, and
the ring updates to match the new port.

View File

@ -87,8 +87,8 @@
{% set _update = device.update({'weight': weight}) %} {% set _update = device.update({'weight': weight}) %}
{% set _update = device.update({'region': region}) %} {% set _update = device.update({'region': region}) %}
{% set _update = device.update({'zone': zone}) %} {% set _update = device.update({'zone': zone}) %}
{% set _update = device.update({'repl_ip': repl_ip}) %} {% set _update = device.update({'replication_ip': repl_ip}) %}
{% set _update = device.update({'repl_port': repl_port|int}) %} {% set _update = device.update({'replication_port': repl_port|int}) %}
{% set _update = device.update({'ip': storage_ip}) %} {% set _update = device.update({'ip': storage_ip}) %}
{% set _update = device.update({'port': storage_port|int}) %} {% set _update = device.update({'port': storage_port|int}) %}
{### Append the device to the drives list of the builder dict #} {### Append the device to the drives list of the builder dict #}

View File

@ -27,7 +27,9 @@ import threading
USAGE = "usage: %prog -f <swift_ring.contents> -r <managed_region>" USAGE = "usage: %prog -f <swift_ring.contents> -r <managed_region>"
DEVICE_KEY = "%(ip)s:%(port)d/%(device)s" DEVICE_KEY = "%(ip)s/%(device)s"
FULL_HOST_KEY = "%(ip)s:%(port)dR%(replication_ip)s:" \
"%(replication_port)d/%(device)s"
class RingValidationError(Exception): class RingValidationError(Exception):
@ -82,28 +84,22 @@ def update_host_in_ring(build_file, new_host, old_host, validate=False):
'be done when the drive is added' % devstr) 'be done when the drive is added' % devstr)
try: try:
r_ip = new_host.get('repl_ip', new_host['ip']) old_host_str = FULL_HOST_KEY % old_host
r_port = new_host.get('repl_port', new_host['port']) new_host_str = FULL_HOST_KEY % new_host
weight = new_host.get('weight')
old_r_ip = old_host['replication_ip'] new_weight = new_host.get('weight')
old_r_port = old_host['replication_port'] old_weight = old_host.get('weight')
if r_ip != old_r_ip or r_port != old_r_port: if new_host_str != old_host_str:
host_d = {'r_ip': r_ip, 'r_port': r_port}
host_d.update(new_host)
host_str = (
"%(ip)s:%(port)dR%(r_ip)s:%(r_port)d/%(device)s" % host_d
)
if not validate: if not validate:
run_and_wait(rb_main, ["swift-ring-builder", build_file, run_and_wait(rb_main, ["swift-ring-builder", build_file,
"set_info", DEVICE_KEY % new_host, "set_info", old_host_str,
host_str]) new_host_str])
except Exception as ex: except Exception as ex:
raise RingValidationError(ex) raise RingValidationError(ex)
if weight != old_host['weight'] and not validate: if new_weight != old_weight and not validate:
change_host_weight(build_file, DEVICE_KEY % new_host, weight) change_host_weight(build_file, FULL_HOST_KEY % new_host, new_weight)
def add_host_to_ring(build_file, host, validate=False): def add_host_to_ring(build_file, host, validate=False):
@ -111,17 +107,8 @@ def add_host_to_ring(build_file, host, validate=False):
try: try:
if host.get('region') is not None: if host.get('region') is not None:
host_str += 'r%(region)d' % host host_str += 'r%(region)d' % host
host_str += "z%d" % (host.get('zone')) host_str += "z%(zone)d-" % host
host_str += "-%(ip)s:%(port)d" % host host_str += FULL_HOST_KEY % host
if host.get('repl_ip'):
r_ip = host['repl_ip']
r_port = host.get('repl_port', host['port'])
host_str += "R%s:%d" % (r_ip, r_port)
elif host.get('repl_port'):
r_ip = host.get('repl_ip', host['ip'])
r_port = host['repl_port']
host_str += "R%s:%d" % (r_ip, r_port)
host_str += "/%(device)s" % host
weight = host.get('weight') weight = host.get('weight')
except Exception as ex: except Exception as ex:
raise RingValidationError(ex) raise RingValidationError(ex)
@ -203,6 +190,11 @@ def build_ring(build_name, repl, min_part_hours, part_power, hosts,
run_and_wait( run_and_wait(
rb_main, ["swift-ring-builder", build_file, "rebalance"] rb_main, ["swift-ring-builder", build_file, "rebalance"]
) )
# In case no changes that require a rebalance have happened
# We may still need to write the ring for device changes.
run_and_wait(
rb_main, ["swift-ring-builder", build_file, "write_ring"]
)
def main(setup, region, reset_mph_clock): def main(setup, region, reset_mph_clock):

View File

@ -24,6 +24,8 @@ import sys
USAGE = "usage: %prog -f <swift_ring.contentsa> -r <managed_region>" USAGE = "usage: %prog -f <swift_ring.contentsa> -r <managed_region>"
DEVICE_KEY = "%(ip)s:%(port)d/%(device)s" DEVICE_KEY = "%(ip)s:%(port)d/%(device)s"
FULL_HOST_KEY = "%(ip)s:%(port)dR%(replication_ip)s:" \
"%(replication_port)d/%(device)s_w%(weight)d"
class RingComparisonError(Exception): class RingComparisonError(Exception):
@ -69,21 +71,12 @@ def check_host_settings(content_host, ring_host):
raise RingComparisonError('Region on device %s differs to the ring.' raise RingComparisonError('Region on device %s differs to the ring.'
% devstr) % devstr)
content_repl_ip = content_host.get('repl_ip', content_host['ip']) content_host_str = FULL_HOST_KEY % content_host
content_repl_port = content_host.get('repl_port', content_host['port']) ring_host_str = FULL_HOST_KEY % ring_host
content_weight = content_host.get('weight')
ring_repl_ip = ring_host['replication_ip'] if content_host_str != ring_host_str:
ring_repl_port = ring_host['replication_port'] raise RingComparisonError('Content device %(content_host_str)s differs'
ring_weight = ring_host['weight'] ' to the ring device %(ring_host_str)s.')
if content_repl_ip != ring_repl_ip:
raise RingComparisonError('Replication IP for device %s differs '
'to the ring.' % devstr)
if content_repl_port != ring_repl_port:
raise RingComparisonError('Replication Port for device %s differs '
'to the ring.' % devstr)
if content_weight != ring_weight:
raise RingComparisonError('Device weight for device %s differs to the '
'ring.' % devstr)
def check_ring(build_name, repl, min_part_hours, part_power, content_hosts, def check_ring(build_name, repl, min_part_hours, part_power, content_hosts,