Skip to content

Commit 3e5b5f3

Browse files
committed
Refactor config drive metadata service
Refactor the existing ConfigDrive Metadata service so that another metadata format implemenation like NoCloud can be easily added. Now, the drive label and the metadata file can be set in the constructor, making it easy to add another config drive metadata service with different label or path. Change-Id: I8dd8160dfbe9f529bb8f30ab85181f264c18833e
1 parent 32103bd commit 3e5b5f3

File tree

7 files changed

+329
-181
lines changed

7 files changed

+329
-181
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2012 Cloudbase Solutions Srl
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import os
16+
import shutil
17+
18+
from oslo_log import log as oslo_logging
19+
20+
from cloudbaseinit import conf as cloudbaseinit_conf
21+
from cloudbaseinit import constant
22+
from cloudbaseinit import exception
23+
from cloudbaseinit.metadata.services import base
24+
from cloudbaseinit.metadata.services.osconfigdrive import factory
25+
26+
CONF = cloudbaseinit_conf.CONF
27+
LOG = oslo_logging.getLogger(__name__)
28+
29+
CD_TYPES = constant.CD_TYPES
30+
CD_LOCATIONS = constant.CD_LOCATIONS
31+
32+
33+
class BaseConfigDriveService(base.BaseMetadataService):
34+
35+
def __init__(self, drive_label, metadata_file):
36+
super(BaseConfigDriveService, self).__init__()
37+
self._drive_label = drive_label
38+
self._metadata_file = metadata_file
39+
self._metadata_path = None
40+
self._searched_types = set()
41+
self._searched_locations = set()
42+
43+
def _preprocess_options(self):
44+
self._searched_types = set(CONF.config_drive.types)
45+
self._searched_locations = set(CONF.config_drive.locations)
46+
47+
# Deprecation backward compatibility.
48+
if CONF.config_drive.raw_hdd:
49+
self._searched_types.add("iso")
50+
self._searched_locations.add("hdd")
51+
if CONF.config_drive.cdrom:
52+
self._searched_types.add("iso")
53+
self._searched_locations.add("cdrom")
54+
if CONF.config_drive.vfat:
55+
self._searched_types.add("vfat")
56+
self._searched_locations.add("hdd")
57+
58+
# Check for invalid option values.
59+
if self._searched_types | CD_TYPES != CD_TYPES:
60+
raise exception.CloudbaseInitException(
61+
"Invalid Config Drive types %s", self._searched_types)
62+
if self._searched_locations | CD_LOCATIONS != CD_LOCATIONS:
63+
raise exception.CloudbaseInitException(
64+
"Invalid Config Drive locations %s", self._searched_locations)
65+
66+
def load(self):
67+
super(BaseConfigDriveService, self).load()
68+
69+
self._preprocess_options()
70+
self._mgr = factory.get_config_drive_manager()
71+
found = self._mgr.get_config_drive_files(
72+
drive_label=self._drive_label,
73+
metadata_file=self._metadata_file,
74+
searched_types=self._searched_types,
75+
searched_locations=self._searched_locations)
76+
77+
if found:
78+
self._metadata_path = self._mgr.target_path
79+
LOG.debug('Metadata copied to folder: %r', self._metadata_path)
80+
return found
81+
82+
def _get_data(self, path):
83+
norm_path = os.path.normpath(os.path.join(self._metadata_path, path))
84+
try:
85+
with open(norm_path, 'rb') as stream:
86+
return stream.read()
87+
except IOError:
88+
raise base.NotExistingMetadataException()
89+
90+
def cleanup(self):
91+
LOG.debug('Deleting metadata folder: %r', self._mgr.target_path)
92+
shutil.rmtree(self._mgr.target_path, ignore_errors=True)
93+
self._metadata_path = None
Lines changed: 6 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2012 Cloudbase Solutions Srl
1+
# Copyright 2020 Cloudbase Solutions Srl
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License"); you may
44
# not use this file except in compliance with the License. You may obtain
@@ -12,77 +12,19 @@
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
1414

15-
import os
16-
import shutil
17-
1815
from oslo_log import log as oslo_logging
1916

2017
from cloudbaseinit import conf as cloudbaseinit_conf
21-
from cloudbaseinit import constant
22-
from cloudbaseinit import exception
23-
from cloudbaseinit.metadata.services import base
18+
from cloudbaseinit.metadata.services import baseconfigdrive
2419
from cloudbaseinit.metadata.services import baseopenstackservice
25-
from cloudbaseinit.metadata.services.osconfigdrive import factory
2620

2721
CONF = cloudbaseinit_conf.CONF
2822
LOG = oslo_logging.getLogger(__name__)
2923

30-
CD_TYPES = constant.CD_TYPES
31-
CD_LOCATIONS = constant.CD_LOCATIONS
32-
3324

34-
class ConfigDriveService(baseopenstackservice.BaseOpenStackService):
25+
class ConfigDriveService(baseconfigdrive.BaseConfigDriveService,
26+
baseopenstackservice.BaseOpenStackService):
3527

3628
def __init__(self):
37-
super(ConfigDriveService, self).__init__()
38-
self._metadata_path = None
39-
40-
def _preprocess_options(self):
41-
self._searched_types = set(CONF.config_drive.types)
42-
self._searched_locations = set(CONF.config_drive.locations)
43-
44-
# Deprecation backward compatibility.
45-
if CONF.config_drive.raw_hdd:
46-
self._searched_types.add("iso")
47-
self._searched_locations.add("hdd")
48-
if CONF.config_drive.cdrom:
49-
self._searched_types.add("iso")
50-
self._searched_locations.add("cdrom")
51-
if CONF.config_drive.vfat:
52-
self._searched_types.add("vfat")
53-
self._searched_locations.add("hdd")
54-
55-
# Check for invalid option values.
56-
if self._searched_types | CD_TYPES != CD_TYPES:
57-
raise exception.CloudbaseInitException(
58-
"Invalid Config Drive types %s", self._searched_types)
59-
if self._searched_locations | CD_LOCATIONS != CD_LOCATIONS:
60-
raise exception.CloudbaseInitException(
61-
"Invalid Config Drive locations %s", self._searched_locations)
62-
63-
def load(self):
64-
super(ConfigDriveService, self).load()
65-
66-
self._preprocess_options()
67-
self._mgr = factory.get_config_drive_manager()
68-
found = self._mgr.get_config_drive_files(
69-
searched_types=self._searched_types,
70-
searched_locations=self._searched_locations)
71-
72-
if found:
73-
self._metadata_path = self._mgr.target_path
74-
LOG.debug('Metadata copied to folder: %r', self._metadata_path)
75-
return found
76-
77-
def _get_data(self, path):
78-
norm_path = os.path.normpath(os.path.join(self._metadata_path, path))
79-
try:
80-
with open(norm_path, 'rb') as stream:
81-
return stream.read()
82-
except IOError:
83-
raise base.NotExistingMetadataException()
84-
85-
def cleanup(self):
86-
LOG.debug('Deleting metadata folder: %r', self._mgr.target_path)
87-
shutil.rmtree(self._mgr.target_path, ignore_errors=True)
88-
self._metadata_path = None
29+
super(ConfigDriveService, self).__init__(
30+
'config-2', 'openstack\\latest\\meta_data.json')

cloudbaseinit/metadata/services/osconfigdrive/base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,7 @@ def __init__(self):
2525
self.target_path = tempfile.mkdtemp()
2626

2727
@abc.abstractmethod
28-
def get_config_drive_files(self, check_types=None, check_locations=None):
28+
def get_config_drive_files(self, drive_label, metadata_file,
29+
check_types=None, check_locations=None,
30+
):
2931
pass

cloudbaseinit/metadata/services/osconfigdrive/windows.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
CONF = cloudbaseinit_conf.CONF
3333
LOG = oslo_logging.getLogger(__name__)
3434

35-
CONFIG_DRIVE_LABEL = 'config-2'
3635
MAX_SECTOR_SIZE = 4096
3736
# Absolute offset values and the ISO magic string.
3837
OFFSET_BOOT_RECORD = 0x8000
@@ -50,18 +49,25 @@ def __init__(self):
5049
super(WindowsConfigDriveManager, self).__init__()
5150
self._osutils = osutils_factory.get_os_utils()
5251

53-
def _check_for_config_drive(self, drive):
52+
def _meta_data_file_exists(self, drive, metadata_file):
53+
metadata_file = os.path.join(drive, metadata_file)
54+
55+
if os.path.exists(metadata_file):
56+
return True
57+
58+
LOG.debug('%s not found', metadata_file)
59+
return False
60+
61+
def _check_for_config_drive(self, drive, required_drive_label,
62+
metadata_file):
5463
label = self._osutils.get_volume_label(drive)
55-
if label and label.lower() == CONFIG_DRIVE_LABEL:
56-
if os.path.exists(os.path.join(drive,
57-
'openstack\\latest\\meta_data.json')):
58-
LOG.info('Config Drive found on %s', drive)
59-
return True
60-
LOG.debug('%s\openstack\latest\meta_data.json not '
61-
'found', drive)
64+
if label and label.lower() == required_drive_label and \
65+
self._meta_data_file_exists(drive, metadata_file):
66+
LOG.info('Config Drive found on %s', drive)
67+
return True
6268
LOG.debug("Looking for a Config Drive with label '%s' on '%s'. "
6369
"Found mismatching label '%s'.",
64-
CONFIG_DRIVE_LABEL, drive, label)
70+
required_drive_label, drive, label)
6571
return False
6672

6773
def _get_iso_file_size(self, device):
@@ -137,20 +143,21 @@ def _extract_iso_from_devices(self, devices):
137143
os.remove(iso_file_path)
138144
return extracted
139145

140-
def _get_config_drive_from_cdrom_drive(self):
146+
def _get_config_drive_from_cdrom_drive(self, drive_label, metadata_file):
141147
for drive_letter in self._osutils.get_cdrom_drives():
142-
if self._check_for_config_drive(drive_letter):
148+
if self._check_for_config_drive(drive_letter, drive_label,
149+
metadata_file):
143150
os.rmdir(self.target_path)
144151
shutil.copytree(drive_letter, self.target_path)
145152
return True
146153

147154
return False
148155

149-
def _get_config_drive_from_raw_hdd(self):
156+
def _get_config_drive_from_raw_hdd(self, drive_label, metadata_file):
150157
disks = map(disk.Disk, self._osutils.get_physical_disks())
151158
return self._extract_iso_from_devices(disks)
152159

153-
def _get_config_drive_from_vfat(self):
160+
def _get_config_drive_from_vfat(self, drive_label, metadata_file):
154161
for drive_path in self._osutils.get_physical_disks():
155162
if vfat.is_vfat_drive(self._osutils, drive_path):
156163
LOG.info('Config Drive found on disk %r', drive_path)
@@ -159,7 +166,7 @@ def _get_config_drive_from_vfat(self):
159166
return True
160167
return False
161168

162-
def _get_config_drive_from_partition(self):
169+
def _get_config_drive_from_partition(self, drive_label, metadata_file):
163170
for disk_path in self._osutils.get_physical_disks():
164171
physical_drive = disk.Disk(disk_path)
165172
with physical_drive:
@@ -169,22 +176,24 @@ def _get_config_drive_from_partition(self):
169176
return True
170177
return False
171178

172-
def _get_config_drive_from_volume(self):
179+
def _get_config_drive_from_volume(self, drive_label, metadata_file):
173180
"""Look through all the volumes for config drive."""
174181
volumes = self._osutils.get_volumes()
175182
for volume in volumes:
176-
if self._check_for_config_drive(volume):
183+
if self._check_for_config_drive(volume, drive_label,
184+
metadata_file):
177185
os.rmdir(self.target_path)
178186
shutil.copytree(volume, self.target_path)
179187
return True
180188
return False
181189

182-
def _get_config_drive_files(self, cd_type, cd_location):
190+
def _get_config_drive_files(self, drive_label, metadata_file,
191+
cd_type, cd_location):
183192
try:
184193
get_config_drive = self.config_drive_type_location.get(
185194
"{}_{}".format(cd_location, cd_type))
186195
if get_config_drive:
187-
return get_config_drive()
196+
return get_config_drive(drive_label, metadata_file)
188197
else:
189198
LOG.debug("Irrelevant type %(type)s in %(location)s "
190199
"location; skip",
@@ -196,16 +205,19 @@ def _get_config_drive_files(self, cd_type, cd_location):
196205

197206
return False
198207

199-
def get_config_drive_files(self, searched_types=None,
200-
searched_locations=None):
208+
def get_config_drive_files(self, drive_label, metadata_file,
209+
searched_types=None, searched_locations=None):
201210
searched_types = searched_types or []
202211
searched_locations = searched_locations or []
203212

204213
for cd_type, cd_location in itertools.product(searched_types,
205214
searched_locations):
206-
LOG.debug('Looking for Config Drive %(type)s in %(location)s',
207-
{"type": cd_type, "location": cd_location})
208-
if self._get_config_drive_files(cd_type, cd_location):
215+
LOG.debug('Looking for Config Drive %(type)s in %(location)s '
216+
'with expected label %(drive_label)s',
217+
{"type": cd_type, "location": cd_location,
218+
"drive_label": drive_label})
219+
if self._get_config_drive_files(drive_label, metadata_file,
220+
cd_type, cd_location):
209221
return True
210222

211223
return False

0 commit comments

Comments
 (0)