
Minor cleanups from feedback on earlier patches. Related to blueprint stable-compute-uuid Change-Id: I00505f1df47b46ed36645c781354258e255f0dcc
109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
# Copyright 2022 Red Hat, inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import logging
|
|
import os
|
|
import uuid
|
|
|
|
from oslo_utils import uuidutils
|
|
|
|
import nova.conf
|
|
from nova import exception
|
|
|
|
CONF = nova.conf.CONF
|
|
LOG = logging.getLogger(__name__)
|
|
COMPUTE_ID_FILE = 'compute_id'
|
|
LOCAL_NODE_UUID = None
|
|
|
|
|
|
def write_local_node_uuid(node_uuid):
|
|
# We only ever write an identity file in the CONF.state_path
|
|
# location
|
|
fn = os.path.join(CONF.state_path, COMPUTE_ID_FILE)
|
|
|
|
# Try to create the identity file and write our uuid into it. Fail
|
|
# if the file exists (since it shouldn't if we made it here).
|
|
try:
|
|
with open(fn, 'x') as f:
|
|
f.write(node_uuid)
|
|
except FileExistsError:
|
|
# If the file exists, we must either fail or re-survey all the
|
|
# potential files. If we just read and return it, it could be
|
|
# inconsistent with files in the other locations.
|
|
raise exception.InvalidNodeConfiguration(
|
|
reason='Identity file %s appeared unexpectedly' % fn)
|
|
except Exception as e:
|
|
raise exception.InvalidNodeConfiguration(
|
|
reason='Unable to write uuid to %s: %s' % (fn, e))
|
|
|
|
LOG.info('Wrote node identity %s to %s', node_uuid, fn)
|
|
|
|
|
|
def read_local_node_uuid():
|
|
locations = ([os.path.dirname(f) for f in CONF.config_file] +
|
|
[CONF.state_path])
|
|
|
|
uuids = []
|
|
found = []
|
|
for location in locations:
|
|
fn = os.path.join(location, COMPUTE_ID_FILE)
|
|
try:
|
|
# UUIDs should be 36 characters in canonical format. Read
|
|
# a little more to be graceful about whitespace in/around
|
|
# the actual value we want to read. However, it must parse
|
|
# to a legit UUID once we strip the whitespace.
|
|
with open(fn) as f:
|
|
content = f.read(40)
|
|
node_uuid = str(uuid.UUID(content.strip()))
|
|
except FileNotFoundError:
|
|
continue
|
|
except ValueError:
|
|
raise exception.InvalidNodeConfiguration(
|
|
reason='Unable to parse UUID from %s' % fn)
|
|
uuids.append(node_uuid)
|
|
found.append(fn)
|
|
|
|
if uuids:
|
|
# Any identities we found must be consistent, or we fail
|
|
first = uuids[0]
|
|
for i, (node_uuid, fn) in enumerate(zip(uuids, found)):
|
|
if node_uuid != first:
|
|
raise exception.InvalidNodeConfiguration(
|
|
reason='UUID %s in %s does not match %s' % (
|
|
node_uuid, fn, uuids[i - 1]))
|
|
LOG.info('Determined node identity %s from %s', first, found[0])
|
|
return first
|
|
else:
|
|
return None
|
|
|
|
|
|
def get_local_node_uuid():
|
|
"""Read or create local node uuid file.
|
|
|
|
:returns: UUID string read from file, or generated
|
|
"""
|
|
global LOCAL_NODE_UUID
|
|
|
|
if LOCAL_NODE_UUID is not None:
|
|
return LOCAL_NODE_UUID
|
|
|
|
node_uuid = read_local_node_uuid()
|
|
if not node_uuid:
|
|
node_uuid = uuidutils.generate_uuid()
|
|
LOG.info('Generated node identity %s', node_uuid)
|
|
write_local_node_uuid(node_uuid)
|
|
|
|
LOCAL_NODE_UUID = node_uuid
|
|
return node_uuid
|