1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# 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
|