kiwi.runtime_config
1# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved. 2# 3# This file is part of kiwi. 4# 5# kiwi is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# kiwi is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with kiwi. If not, see <http://www.gnu.org/licenses/> 17# 18import os 19import logging 20import functools 21from typing import ( 22 Literal, List, Optional, NamedTuple, Callable, Dict, Any 23) 24import yaml 25 26# project 27import kiwi.defaults as defaults 28 29from kiwi.defaults import Defaults 30from kiwi.utils.size import StringToSize 31from kiwi.utils.checksum import Checksum 32from kiwi.exceptions import ( 33 KiwiRuntimeConfigFormatError, 34 KiwiRuntimeConfigFileError 35) 36 37log = logging.getLogger('kiwi') 38 39RUNTIME_CONFIG: Optional[Dict[str, Any]] = None 40 41 42class ShasumT(NamedTuple): 43 suffix: str 44 digest: Callable 45 46 47class RuntimeConfig: 48 """ 49 **Implements reading of runtime configuration files:** 50 51 1. vendor: /usr/share/kiwi/kiwi.yml + /usr/share/kiwi/kiwi.yml.d/*.yml 52 2. admin: /etc/kiwi.yml + /etc/kiwi.yml.d/*.yml 53 3. ~/.config/kiwi/config.yml 54 4. Check for --config provided from the CLI 55 56 The KIWI runtime configuration file is a yaml formatted file 57 containing information to control the behavior of the tools 58 used by KIWI on the build host. 59 60 :param bool reread: reread runtime config 61 """ 62 def __init__(self, reread: bool = False): 63 global RUNTIME_CONFIG 64 65 if RUNTIME_CONFIG is None or reread: 66 custom_config_file = defaults.CUSTOM_RUNTIME_CONFIG_FILE 67 config_files = [] 68 # 1. vendor 69 config_file = defaults.USR_RUNTIME_CONFIG_FILE 70 if os.path.exists(config_file): 71 config_files.append(config_file) 72 config_files += self._read_drop_ins_dir( 73 defaults.USR_RUNTIME_CONFIG_DIR 74 ) 75 # 2. admin 76 config_file = defaults.ETC_RUNTIME_CONFIG_FILE 77 if os.path.exists(config_file): 78 config_files.append(config_file) 79 config_files += self._read_drop_ins_dir( 80 defaults.ETC_RUNTIME_CONFIG_DIR 81 ) 82 # 3. home 83 if self._home_path(): 84 config_file = os.sep.join( 85 [self._home_path(), '.config', 'kiwi', 'config.yml'] 86 ) 87 if os.path.exists(config_file): 88 config_files.append(config_file) 89 # 4. cmdline 90 if custom_config_file: 91 config_file = custom_config_file 92 if not os.path.isfile(config_file): 93 raise KiwiRuntimeConfigFileError( 94 f'Custom config file {config_file!r} not found' 95 ) 96 config_files.append(config_file) 97 # read all config files... 98 RUNTIME_CONFIG = {} 99 for config_file in config_files: 100 log.info( 101 f'Reading runtime config file: {config_file!r}' 102 ) 103 with open(config_file, 'r') as config: 104 RUNTIME_CONFIG.update(yaml.safe_load(config) or {}) 105 106 def get_credentials_verification_metadata_signing_key_file(self) -> str: 107 """ 108 Return verification metadata signing key file, used for 109 signature creation of rootfs verification metadata: 110 111 credentials: 112 - verification_metadata_signing_key_file: ... 113 114 There is no default value for this setting available 115 116 :return: file path name or '' 117 118 :rtype: str 119 """ 120 signing_key_file = self._get_attribute( 121 element='credentials', 122 attribute='verification_metadata_signing_key_file' 123 ) 124 return signing_key_file if signing_key_file else '' 125 126 def get_obs_download_server_url(self) -> str: 127 """ 128 Return URL of buildservice download server in: 129 130 obs: 131 - download_url: ... 132 133 if no configuration exists the downloadserver from 134 the Defaults class is returned 135 136 :return: URL type data 137 138 :rtype: str 139 """ 140 obs_download_server_url = self._get_attribute( 141 element='obs', attribute='download_url' 142 ) 143 return obs_download_server_url if obs_download_server_url else \ 144 Defaults.get_obs_download_server_url() 145 146 def get_obs_api_server_url(self) -> str: 147 """ 148 Return URL of buildservice API server in: 149 150 obs: 151 - api_url: ... 152 153 if no configuration exists the API server from 154 the Defaults class is returned 155 156 :return: URL type data 157 158 :rtype: str 159 """ 160 obs_api_server_url = self._get_attribute( 161 element='obs', attribute='api_url' 162 ) 163 return obs_api_server_url if obs_api_server_url else \ 164 Defaults.get_obs_api_server_url() 165 166 def get_obs_api_credentials(self) -> List[str]: 167 """ 168 Return OBS API credentials if configured: 169 170 obs: 171 - user: 172 - user_name: user_credentials 173 174 :return: List of Dicts with credentials per user 175 176 :rtype: list 177 """ 178 obs_users = self._get_attribute(element='obs', attribute='user') or [] 179 return obs_users 180 181 def is_obs_public(self) -> bool: 182 """ 183 Check if the buildservice configuration is public or private in: 184 185 obs: 186 - public: true|false 187 188 if no configuration exists we assume to be public 189 190 :return: True or False 191 192 :rtype: bool 193 """ 194 obs_public = self._get_attribute(element='obs', attribute='public') 195 if obs_public is None: 196 # if the privacy attribute is not set we assume to be public 197 obs_public = True 198 return bool(obs_public) 199 200 def get_package_changes(self, default: bool = True) -> bool: 201 """ 202 Return boolean value to express if the image build and bundle 203 should contain a .changes file. The .changes file contains 204 the package changelog information from all packages installed 205 into the image. 206 207 bundle: 208 - has_package_changes: true|false 209 210 By default the creation is switched on. 211 When building in the Open Build Service the default is 212 switched off because obs provides a .report file containing 213 the same information. 214 215 :param bool default: Default value 216 217 :return: True or False 218 219 :rtype: bool 220 """ 221 bundle_package_changes = self._get_attribute( 222 element='bundle', attribute='has_package_changes' 223 ) 224 if bundle_package_changes is None: 225 if Defaults.is_buildservice_worker(): 226 bundle_package_changes = False 227 else: 228 bundle_package_changes = default 229 return bool(bundle_package_changes) 230 231 def get_bundle_compression(self, default: bool = True) -> bool: 232 """ 233 Return boolean value to express if the image bundle should 234 contain XZ compressed image results or not. 235 236 bundle: 237 - compress: true|false 238 239 If compression of image build results is activated the size 240 of the bundle is smaller and the download speed increases. 241 However the image must be uncompressed before use 242 243 If no compression is explicitly configured, the provided 244 default value applies 245 246 :param bool default: Default value 247 248 :return: True or False 249 250 :rtype: bool 251 """ 252 bundle_compress = self._get_attribute( 253 element='bundle', attribute='compress' 254 ) 255 if bundle_compress is None: 256 bundle_compress = default 257 return bool(bundle_compress) 258 259 def get_checksum_handler( 260 self, 261 source_filename: str, 262 target_filename: Optional[str] = None, 263 default: str = '256', 264 bundle_lookup: bool = False 265 ) -> ShasumT: 266 """ 267 Return a ShasumT with information about the configured 268 shasum suffix name and the digest(Checksum) callable. The 269 following configuration setting allows to configure the 270 size of the checksum: 271 272 shasum: 273 - size: 256 274 275 bundle: 276 - shasum_size: "256" 277 278 Instructs kiwi to use the provided shasum size. Supported 279 values are 256 (default) and 512. In case of an unsupported 280 value the default is used. A value from the bundle section 281 takes precedence over the global shasum size specified 282 in the shasum section for creating bundle results. If no 283 information for bundle results is specified, the global 284 shasum size or the default applies. 285 286 :param str source_filename: filename to calculate checksum for 287 :param str target_filename: filename to write checksum to 288 :param str default: default size set to 256 289 290 :rtype: ShasumT 291 """ 292 supported_shasums = { 293 '256': ShasumT( 294 suffix='.sha256', 295 digest=functools.partial( 296 Checksum(source_filename).sha256, target_filename 297 ) 298 ), 299 '512': ShasumT( 300 suffix='.sha512', 301 digest=functools.partial( 302 Checksum(source_filename).sha512, target_filename 303 ) 304 ) 305 } 306 shasum_size = self._get_attribute( 307 element='shasum', attribute='size' 308 ) 309 if bundle_lookup: 310 bundle_shasum_size = self._get_attribute( 311 element='bundle', attribute='shasum_size' 312 ) 313 if bundle_shasum_size: 314 shasum_size = bundle_shasum_size 315 if supported_shasums.get(shasum_size): 316 return supported_shasums[shasum_size] 317 return supported_shasums['256'] 318 319 def get_xz_options(self) -> Optional[List[str]]: 320 """ 321 Return list of XZ compression options in: 322 323 xz: 324 - options: ... 325 326 if no configuration exists None is returned 327 328 :return: 329 Contains list of options 330 331 .. code:: python 332 333 ['--option=value'] 334 335 :rtype: list 336 """ 337 xz_options = self._get_attribute(element='xz', attribute='options') 338 return xz_options.split() if xz_options else None 339 340 def get_container_compression(self) -> bool: 341 """ 342 Return compression for container images 343 344 container: 345 - compress: xz|none|true|false 346 347 if no or invalid configuration data is provided, the default 348 compression from the Defaults class is returned 349 350 :return: True or False 351 352 :rtype: bool 353 """ 354 container_compression = self._get_attribute( 355 element='container', attribute='compress' 356 ) 357 if container_compression is None: 358 return Defaults.get_container_compression() 359 elif 'xz' == container_compression or container_compression is True: 360 return True 361 elif 'none' == container_compression or container_compression is False: 362 return False 363 else: 364 log.warning( 365 'Skipping invalid container compression: {0}'.format( 366 container_compression 367 ) 368 ) 369 return Defaults.get_container_compression() 370 371 def get_iso_tool_category(self) -> str: 372 """ 373 Return tool category which should be used to build iso images 374 375 iso: 376 - tool_category: xorriso 377 378 if no or invalid configuration exists the default tool category 379 from the Defaults class is returned 380 381 :return: A name 382 383 :rtype: str 384 """ 385 iso_tool_category = self._get_attribute( 386 element='iso', attribute='tool_category' 387 ) 388 if not iso_tool_category: 389 return Defaults.get_iso_tool_category() 390 elif 'xorriso' in iso_tool_category: 391 return iso_tool_category 392 else: 393 log.warning( 394 'Skipping invalid iso tool category: {0}'.format( 395 iso_tool_category 396 ) 397 ) 398 return Defaults.get_iso_tool_category() 399 400 def get_iso_media_tag_tool(self) -> Literal['checkmedia', 'isomd5sum']: 401 """ 402 Return media tag tool used to checksum iso images 403 404 iso: 405 - media_tag_tool: checkmedia 406 407 if no or invalid configuration exists the default media tagger 408 from the Defaults class is returned 409 410 :return: A name 411 412 :rtype: str 413 """ 414 iso_media_tag_tool = self._get_attribute( 415 element='iso', attribute='media_tag_tool' 416 ) 417 if not iso_media_tag_tool: 418 return Defaults.get_iso_media_tag_tool() 419 elif 'checkmedia' in iso_media_tag_tool: 420 return iso_media_tag_tool 421 elif 'isomd5sum' in iso_media_tag_tool: 422 return iso_media_tag_tool 423 else: 424 log.warning( 425 'Skipping invalid iso media tag tool: {0}'.format( 426 iso_media_tag_tool 427 ) 428 ) 429 return Defaults.get_iso_media_tag_tool() 430 431 def get_oci_archive_tool(self) -> str: 432 """ 433 Return OCI archive tool which should be used on creation of 434 container archives for OCI compliant images, e.g docker 435 436 oci: 437 - archive_tool: umoci 438 439 if no configuration exists the default tool from the 440 Defaults class is returned 441 442 :return: A name 443 444 :rtype: str 445 """ 446 oci_archive_tool = self._get_attribute( 447 element='oci', attribute='archive_tool' 448 ) 449 return oci_archive_tool or Defaults.get_oci_archive_tool() 450 451 def get_mapper_tool(self) -> str: 452 """ 453 Return partition mapper tool 454 455 mapper: 456 - part_mapper: partx 457 458 if no configuration exists the default tool from the 459 Defaults class is returned 460 461 :return: A name 462 463 :rtype: str 464 """ 465 part_mapper_tool = self._get_attribute( 466 element='mapper', attribute='part_mapper' 467 ) 468 return part_mapper_tool or Defaults.get_part_mapper_tool() 469 470 def get_max_size_constraint(self) -> Optional[int]: 471 """ 472 Returns the maximum allowed size of the built image. The value is 473 returned in bytes and it is specified in build_constraints element 474 with the max_size attribute. The value can be specified in bytes or 475 it can be specified with m=MB or g=GB. 476 477 build_constraints: 478 - max_size: 700m 479 480 if no configuration exists None is returned 481 482 :return: byte value or None 483 484 :rtype: int 485 """ 486 max_size = self._get_attribute( 487 element='build_constraints', attribute='max_size' 488 ) 489 return StringToSize.to_bytes(max_size) if max_size else None 490 491 def get_disabled_runtime_checks(self) -> List[str]: 492 """ 493 Returns disabled runtime checks. Checks can be disabled with: 494 495 runtime_checks: 496 - disable: check_container_tool_chain_installed 497 498 if the provided string does not match any RuntimeChecker method it is 499 just ignored. 500 """ 501 disabled_checks = self._get_attribute( 502 element='runtime_checks', attribute='disable' 503 ) or [] 504 for check in disabled_checks: 505 log.warning(f'Runtime check: {check}: disabled') 506 return disabled_checks 507 508 def _get_attribute(self, element: str, attribute: str): 509 if RUNTIME_CONFIG: 510 try: 511 if element in RUNTIME_CONFIG: 512 for attribute_dict in RUNTIME_CONFIG[element]: 513 if attribute in attribute_dict: 514 return attribute_dict[attribute] 515 except Exception as issue: 516 raise KiwiRuntimeConfigFormatError( 517 f'{type(issue).__name__}: {issue}' 518 ) 519 520 def _home_path(self) -> str: 521 return os.environ.get('HOME') or '' 522 523 def _read_drop_ins_dir(self, config_dir: str) -> List[str]: 524 config_files = [] 525 if os.path.isdir(config_dir): 526 for config_file in sorted(os.listdir(config_dir)): 527 if config_file.endswith('.yml'): 528 config_file_path = os.path.normpath( 529 os.sep.join([config_dir, config_file]) 530 ) 531 config_files.append(config_file_path) 532 return config_files
ShasumT(suffix, digest)
48class RuntimeConfig: 49 """ 50 **Implements reading of runtime configuration files:** 51 52 1. vendor: /usr/share/kiwi/kiwi.yml + /usr/share/kiwi/kiwi.yml.d/*.yml 53 2. admin: /etc/kiwi.yml + /etc/kiwi.yml.d/*.yml 54 3. ~/.config/kiwi/config.yml 55 4. Check for --config provided from the CLI 56 57 The KIWI runtime configuration file is a yaml formatted file 58 containing information to control the behavior of the tools 59 used by KIWI on the build host. 60 61 :param bool reread: reread runtime config 62 """ 63 def __init__(self, reread: bool = False): 64 global RUNTIME_CONFIG 65 66 if RUNTIME_CONFIG is None or reread: 67 custom_config_file = defaults.CUSTOM_RUNTIME_CONFIG_FILE 68 config_files = [] 69 # 1. vendor 70 config_file = defaults.USR_RUNTIME_CONFIG_FILE 71 if os.path.exists(config_file): 72 config_files.append(config_file) 73 config_files += self._read_drop_ins_dir( 74 defaults.USR_RUNTIME_CONFIG_DIR 75 ) 76 # 2. admin 77 config_file = defaults.ETC_RUNTIME_CONFIG_FILE 78 if os.path.exists(config_file): 79 config_files.append(config_file) 80 config_files += self._read_drop_ins_dir( 81 defaults.ETC_RUNTIME_CONFIG_DIR 82 ) 83 # 3. home 84 if self._home_path(): 85 config_file = os.sep.join( 86 [self._home_path(), '.config', 'kiwi', 'config.yml'] 87 ) 88 if os.path.exists(config_file): 89 config_files.append(config_file) 90 # 4. cmdline 91 if custom_config_file: 92 config_file = custom_config_file 93 if not os.path.isfile(config_file): 94 raise KiwiRuntimeConfigFileError( 95 f'Custom config file {config_file!r} not found' 96 ) 97 config_files.append(config_file) 98 # read all config files... 99 RUNTIME_CONFIG = {} 100 for config_file in config_files: 101 log.info( 102 f'Reading runtime config file: {config_file!r}' 103 ) 104 with open(config_file, 'r') as config: 105 RUNTIME_CONFIG.update(yaml.safe_load(config) or {}) 106 107 def get_credentials_verification_metadata_signing_key_file(self) -> str: 108 """ 109 Return verification metadata signing key file, used for 110 signature creation of rootfs verification metadata: 111 112 credentials: 113 - verification_metadata_signing_key_file: ... 114 115 There is no default value for this setting available 116 117 :return: file path name or '' 118 119 :rtype: str 120 """ 121 signing_key_file = self._get_attribute( 122 element='credentials', 123 attribute='verification_metadata_signing_key_file' 124 ) 125 return signing_key_file if signing_key_file else '' 126 127 def get_obs_download_server_url(self) -> str: 128 """ 129 Return URL of buildservice download server in: 130 131 obs: 132 - download_url: ... 133 134 if no configuration exists the downloadserver from 135 the Defaults class is returned 136 137 :return: URL type data 138 139 :rtype: str 140 """ 141 obs_download_server_url = self._get_attribute( 142 element='obs', attribute='download_url' 143 ) 144 return obs_download_server_url if obs_download_server_url else \ 145 Defaults.get_obs_download_server_url() 146 147 def get_obs_api_server_url(self) -> str: 148 """ 149 Return URL of buildservice API server in: 150 151 obs: 152 - api_url: ... 153 154 if no configuration exists the API server from 155 the Defaults class is returned 156 157 :return: URL type data 158 159 :rtype: str 160 """ 161 obs_api_server_url = self._get_attribute( 162 element='obs', attribute='api_url' 163 ) 164 return obs_api_server_url if obs_api_server_url else \ 165 Defaults.get_obs_api_server_url() 166 167 def get_obs_api_credentials(self) -> List[str]: 168 """ 169 Return OBS API credentials if configured: 170 171 obs: 172 - user: 173 - user_name: user_credentials 174 175 :return: List of Dicts with credentials per user 176 177 :rtype: list 178 """ 179 obs_users = self._get_attribute(element='obs', attribute='user') or [] 180 return obs_users 181 182 def is_obs_public(self) -> bool: 183 """ 184 Check if the buildservice configuration is public or private in: 185 186 obs: 187 - public: true|false 188 189 if no configuration exists we assume to be public 190 191 :return: True or False 192 193 :rtype: bool 194 """ 195 obs_public = self._get_attribute(element='obs', attribute='public') 196 if obs_public is None: 197 # if the privacy attribute is not set we assume to be public 198 obs_public = True 199 return bool(obs_public) 200 201 def get_package_changes(self, default: bool = True) -> bool: 202 """ 203 Return boolean value to express if the image build and bundle 204 should contain a .changes file. The .changes file contains 205 the package changelog information from all packages installed 206 into the image. 207 208 bundle: 209 - has_package_changes: true|false 210 211 By default the creation is switched on. 212 When building in the Open Build Service the default is 213 switched off because obs provides a .report file containing 214 the same information. 215 216 :param bool default: Default value 217 218 :return: True or False 219 220 :rtype: bool 221 """ 222 bundle_package_changes = self._get_attribute( 223 element='bundle', attribute='has_package_changes' 224 ) 225 if bundle_package_changes is None: 226 if Defaults.is_buildservice_worker(): 227 bundle_package_changes = False 228 else: 229 bundle_package_changes = default 230 return bool(bundle_package_changes) 231 232 def get_bundle_compression(self, default: bool = True) -> bool: 233 """ 234 Return boolean value to express if the image bundle should 235 contain XZ compressed image results or not. 236 237 bundle: 238 - compress: true|false 239 240 If compression of image build results is activated the size 241 of the bundle is smaller and the download speed increases. 242 However the image must be uncompressed before use 243 244 If no compression is explicitly configured, the provided 245 default value applies 246 247 :param bool default: Default value 248 249 :return: True or False 250 251 :rtype: bool 252 """ 253 bundle_compress = self._get_attribute( 254 element='bundle', attribute='compress' 255 ) 256 if bundle_compress is None: 257 bundle_compress = default 258 return bool(bundle_compress) 259 260 def get_checksum_handler( 261 self, 262 source_filename: str, 263 target_filename: Optional[str] = None, 264 default: str = '256', 265 bundle_lookup: bool = False 266 ) -> ShasumT: 267 """ 268 Return a ShasumT with information about the configured 269 shasum suffix name and the digest(Checksum) callable. The 270 following configuration setting allows to configure the 271 size of the checksum: 272 273 shasum: 274 - size: 256 275 276 bundle: 277 - shasum_size: "256" 278 279 Instructs kiwi to use the provided shasum size. Supported 280 values are 256 (default) and 512. In case of an unsupported 281 value the default is used. A value from the bundle section 282 takes precedence over the global shasum size specified 283 in the shasum section for creating bundle results. If no 284 information for bundle results is specified, the global 285 shasum size or the default applies. 286 287 :param str source_filename: filename to calculate checksum for 288 :param str target_filename: filename to write checksum to 289 :param str default: default size set to 256 290 291 :rtype: ShasumT 292 """ 293 supported_shasums = { 294 '256': ShasumT( 295 suffix='.sha256', 296 digest=functools.partial( 297 Checksum(source_filename).sha256, target_filename 298 ) 299 ), 300 '512': ShasumT( 301 suffix='.sha512', 302 digest=functools.partial( 303 Checksum(source_filename).sha512, target_filename 304 ) 305 ) 306 } 307 shasum_size = self._get_attribute( 308 element='shasum', attribute='size' 309 ) 310 if bundle_lookup: 311 bundle_shasum_size = self._get_attribute( 312 element='bundle', attribute='shasum_size' 313 ) 314 if bundle_shasum_size: 315 shasum_size = bundle_shasum_size 316 if supported_shasums.get(shasum_size): 317 return supported_shasums[shasum_size] 318 return supported_shasums['256'] 319 320 def get_xz_options(self) -> Optional[List[str]]: 321 """ 322 Return list of XZ compression options in: 323 324 xz: 325 - options: ... 326 327 if no configuration exists None is returned 328 329 :return: 330 Contains list of options 331 332 .. code:: python 333 334 ['--option=value'] 335 336 :rtype: list 337 """ 338 xz_options = self._get_attribute(element='xz', attribute='options') 339 return xz_options.split() if xz_options else None 340 341 def get_container_compression(self) -> bool: 342 """ 343 Return compression for container images 344 345 container: 346 - compress: xz|none|true|false 347 348 if no or invalid configuration data is provided, the default 349 compression from the Defaults class is returned 350 351 :return: True or False 352 353 :rtype: bool 354 """ 355 container_compression = self._get_attribute( 356 element='container', attribute='compress' 357 ) 358 if container_compression is None: 359 return Defaults.get_container_compression() 360 elif 'xz' == container_compression or container_compression is True: 361 return True 362 elif 'none' == container_compression or container_compression is False: 363 return False 364 else: 365 log.warning( 366 'Skipping invalid container compression: {0}'.format( 367 container_compression 368 ) 369 ) 370 return Defaults.get_container_compression() 371 372 def get_iso_tool_category(self) -> str: 373 """ 374 Return tool category which should be used to build iso images 375 376 iso: 377 - tool_category: xorriso 378 379 if no or invalid configuration exists the default tool category 380 from the Defaults class is returned 381 382 :return: A name 383 384 :rtype: str 385 """ 386 iso_tool_category = self._get_attribute( 387 element='iso', attribute='tool_category' 388 ) 389 if not iso_tool_category: 390 return Defaults.get_iso_tool_category() 391 elif 'xorriso' in iso_tool_category: 392 return iso_tool_category 393 else: 394 log.warning( 395 'Skipping invalid iso tool category: {0}'.format( 396 iso_tool_category 397 ) 398 ) 399 return Defaults.get_iso_tool_category() 400 401 def get_iso_media_tag_tool(self) -> Literal['checkmedia', 'isomd5sum']: 402 """ 403 Return media tag tool used to checksum iso images 404 405 iso: 406 - media_tag_tool: checkmedia 407 408 if no or invalid configuration exists the default media tagger 409 from the Defaults class is returned 410 411 :return: A name 412 413 :rtype: str 414 """ 415 iso_media_tag_tool = self._get_attribute( 416 element='iso', attribute='media_tag_tool' 417 ) 418 if not iso_media_tag_tool: 419 return Defaults.get_iso_media_tag_tool() 420 elif 'checkmedia' in iso_media_tag_tool: 421 return iso_media_tag_tool 422 elif 'isomd5sum' in iso_media_tag_tool: 423 return iso_media_tag_tool 424 else: 425 log.warning( 426 'Skipping invalid iso media tag tool: {0}'.format( 427 iso_media_tag_tool 428 ) 429 ) 430 return Defaults.get_iso_media_tag_tool() 431 432 def get_oci_archive_tool(self) -> str: 433 """ 434 Return OCI archive tool which should be used on creation of 435 container archives for OCI compliant images, e.g docker 436 437 oci: 438 - archive_tool: umoci 439 440 if no configuration exists the default tool from the 441 Defaults class is returned 442 443 :return: A name 444 445 :rtype: str 446 """ 447 oci_archive_tool = self._get_attribute( 448 element='oci', attribute='archive_tool' 449 ) 450 return oci_archive_tool or Defaults.get_oci_archive_tool() 451 452 def get_mapper_tool(self) -> str: 453 """ 454 Return partition mapper tool 455 456 mapper: 457 - part_mapper: partx 458 459 if no configuration exists the default tool from the 460 Defaults class is returned 461 462 :return: A name 463 464 :rtype: str 465 """ 466 part_mapper_tool = self._get_attribute( 467 element='mapper', attribute='part_mapper' 468 ) 469 return part_mapper_tool or Defaults.get_part_mapper_tool() 470 471 def get_max_size_constraint(self) -> Optional[int]: 472 """ 473 Returns the maximum allowed size of the built image. The value is 474 returned in bytes and it is specified in build_constraints element 475 with the max_size attribute. The value can be specified in bytes or 476 it can be specified with m=MB or g=GB. 477 478 build_constraints: 479 - max_size: 700m 480 481 if no configuration exists None is returned 482 483 :return: byte value or None 484 485 :rtype: int 486 """ 487 max_size = self._get_attribute( 488 element='build_constraints', attribute='max_size' 489 ) 490 return StringToSize.to_bytes(max_size) if max_size else None 491 492 def get_disabled_runtime_checks(self) -> List[str]: 493 """ 494 Returns disabled runtime checks. Checks can be disabled with: 495 496 runtime_checks: 497 - disable: check_container_tool_chain_installed 498 499 if the provided string does not match any RuntimeChecker method it is 500 just ignored. 501 """ 502 disabled_checks = self._get_attribute( 503 element='runtime_checks', attribute='disable' 504 ) or [] 505 for check in disabled_checks: 506 log.warning(f'Runtime check: {check}: disabled') 507 return disabled_checks 508 509 def _get_attribute(self, element: str, attribute: str): 510 if RUNTIME_CONFIG: 511 try: 512 if element in RUNTIME_CONFIG: 513 for attribute_dict in RUNTIME_CONFIG[element]: 514 if attribute in attribute_dict: 515 return attribute_dict[attribute] 516 except Exception as issue: 517 raise KiwiRuntimeConfigFormatError( 518 f'{type(issue).__name__}: {issue}' 519 ) 520 521 def _home_path(self) -> str: 522 return os.environ.get('HOME') or '' 523 524 def _read_drop_ins_dir(self, config_dir: str) -> List[str]: 525 config_files = [] 526 if os.path.isdir(config_dir): 527 for config_file in sorted(os.listdir(config_dir)): 528 if config_file.endswith('.yml'): 529 config_file_path = os.path.normpath( 530 os.sep.join([config_dir, config_file]) 531 ) 532 config_files.append(config_file_path) 533 return config_files
Implements reading of runtime configuration files:
- vendor: /usr/share/kiwi/kiwi.yml + /usr/share/kiwi/kiwi.yml.d/*.yml
- admin: /etc/kiwi.yml + /etc/kiwi.yml.d/*.yml
- ~/.config/kiwi/config.yml
- Check for --config provided from the CLI
The KIWI runtime configuration file is a yaml formatted file containing information to control the behavior of the tools used by KIWI on the build host.
Parameters
- bool reread: reread runtime config
63 def __init__(self, reread: bool = False): 64 global RUNTIME_CONFIG 65 66 if RUNTIME_CONFIG is None or reread: 67 custom_config_file = defaults.CUSTOM_RUNTIME_CONFIG_FILE 68 config_files = [] 69 # 1. vendor 70 config_file = defaults.USR_RUNTIME_CONFIG_FILE 71 if os.path.exists(config_file): 72 config_files.append(config_file) 73 config_files += self._read_drop_ins_dir( 74 defaults.USR_RUNTIME_CONFIG_DIR 75 ) 76 # 2. admin 77 config_file = defaults.ETC_RUNTIME_CONFIG_FILE 78 if os.path.exists(config_file): 79 config_files.append(config_file) 80 config_files += self._read_drop_ins_dir( 81 defaults.ETC_RUNTIME_CONFIG_DIR 82 ) 83 # 3. home 84 if self._home_path(): 85 config_file = os.sep.join( 86 [self._home_path(), '.config', 'kiwi', 'config.yml'] 87 ) 88 if os.path.exists(config_file): 89 config_files.append(config_file) 90 # 4. cmdline 91 if custom_config_file: 92 config_file = custom_config_file 93 if not os.path.isfile(config_file): 94 raise KiwiRuntimeConfigFileError( 95 f'Custom config file {config_file!r} not found' 96 ) 97 config_files.append(config_file) 98 # read all config files... 99 RUNTIME_CONFIG = {} 100 for config_file in config_files: 101 log.info( 102 f'Reading runtime config file: {config_file!r}' 103 ) 104 with open(config_file, 'r') as config: 105 RUNTIME_CONFIG.update(yaml.safe_load(config) or {})
107 def get_credentials_verification_metadata_signing_key_file(self) -> str: 108 """ 109 Return verification metadata signing key file, used for 110 signature creation of rootfs verification metadata: 111 112 credentials: 113 - verification_metadata_signing_key_file: ... 114 115 There is no default value for this setting available 116 117 :return: file path name or '' 118 119 :rtype: str 120 """ 121 signing_key_file = self._get_attribute( 122 element='credentials', 123 attribute='verification_metadata_signing_key_file' 124 ) 125 return signing_key_file if signing_key_file else ''
Return verification metadata signing key file, used for signature creation of rootfs verification metadata:
credentials:
- verification_metadata_signing_key_file: ...
There is no default value for this setting available
Returns
file path name or ''
127 def get_obs_download_server_url(self) -> str: 128 """ 129 Return URL of buildservice download server in: 130 131 obs: 132 - download_url: ... 133 134 if no configuration exists the downloadserver from 135 the Defaults class is returned 136 137 :return: URL type data 138 139 :rtype: str 140 """ 141 obs_download_server_url = self._get_attribute( 142 element='obs', attribute='download_url' 143 ) 144 return obs_download_server_url if obs_download_server_url else \ 145 Defaults.get_obs_download_server_url()
Return URL of buildservice download server in:
obs:
- download_url: ...
if no configuration exists the downloadserver from the Defaults class is returned
Returns
URL type data
147 def get_obs_api_server_url(self) -> str: 148 """ 149 Return URL of buildservice API server in: 150 151 obs: 152 - api_url: ... 153 154 if no configuration exists the API server from 155 the Defaults class is returned 156 157 :return: URL type data 158 159 :rtype: str 160 """ 161 obs_api_server_url = self._get_attribute( 162 element='obs', attribute='api_url' 163 ) 164 return obs_api_server_url if obs_api_server_url else \ 165 Defaults.get_obs_api_server_url()
Return URL of buildservice API server in:
obs:
- api_url: ...
if no configuration exists the API server from the Defaults class is returned
Returns
URL type data
167 def get_obs_api_credentials(self) -> List[str]: 168 """ 169 Return OBS API credentials if configured: 170 171 obs: 172 - user: 173 - user_name: user_credentials 174 175 :return: List of Dicts with credentials per user 176 177 :rtype: list 178 """ 179 obs_users = self._get_attribute(element='obs', attribute='user') or [] 180 return obs_users
Return OBS API credentials if configured:
obs:
- user:
- user_name: user_credentials
Returns
List of Dicts with credentials per user
182 def is_obs_public(self) -> bool: 183 """ 184 Check if the buildservice configuration is public or private in: 185 186 obs: 187 - public: true|false 188 189 if no configuration exists we assume to be public 190 191 :return: True or False 192 193 :rtype: bool 194 """ 195 obs_public = self._get_attribute(element='obs', attribute='public') 196 if obs_public is None: 197 # if the privacy attribute is not set we assume to be public 198 obs_public = True 199 return bool(obs_public)
Check if the buildservice configuration is public or private in:
obs:
- public: true|false
if no configuration exists we assume to be public
Returns
True or False
201 def get_package_changes(self, default: bool = True) -> bool: 202 """ 203 Return boolean value to express if the image build and bundle 204 should contain a .changes file. The .changes file contains 205 the package changelog information from all packages installed 206 into the image. 207 208 bundle: 209 - has_package_changes: true|false 210 211 By default the creation is switched on. 212 When building in the Open Build Service the default is 213 switched off because obs provides a .report file containing 214 the same information. 215 216 :param bool default: Default value 217 218 :return: True or False 219 220 :rtype: bool 221 """ 222 bundle_package_changes = self._get_attribute( 223 element='bundle', attribute='has_package_changes' 224 ) 225 if bundle_package_changes is None: 226 if Defaults.is_buildservice_worker(): 227 bundle_package_changes = False 228 else: 229 bundle_package_changes = default 230 return bool(bundle_package_changes)
Return boolean value to express if the image build and bundle should contain a .changes file. The .changes file contains the package changelog information from all packages installed into the image.
bundle:
- has_package_changes: true|false
By default the creation is switched on. When building in the Open Build Service the default is switched off because obs provides a .report file containing the same information.
Parameters
- bool default: Default value
Returns
True or False
232 def get_bundle_compression(self, default: bool = True) -> bool: 233 """ 234 Return boolean value to express if the image bundle should 235 contain XZ compressed image results or not. 236 237 bundle: 238 - compress: true|false 239 240 If compression of image build results is activated the size 241 of the bundle is smaller and the download speed increases. 242 However the image must be uncompressed before use 243 244 If no compression is explicitly configured, the provided 245 default value applies 246 247 :param bool default: Default value 248 249 :return: True or False 250 251 :rtype: bool 252 """ 253 bundle_compress = self._get_attribute( 254 element='bundle', attribute='compress' 255 ) 256 if bundle_compress is None: 257 bundle_compress = default 258 return bool(bundle_compress)
Return boolean value to express if the image bundle should contain XZ compressed image results or not.
bundle:
- compress: true|false
If compression of image build results is activated the size of the bundle is smaller and the download speed increases. However the image must be uncompressed before use
If no compression is explicitly configured, the provided default value applies
Parameters
- bool default: Default value
Returns
True or False
260 def get_checksum_handler( 261 self, 262 source_filename: str, 263 target_filename: Optional[str] = None, 264 default: str = '256', 265 bundle_lookup: bool = False 266 ) -> ShasumT: 267 """ 268 Return a ShasumT with information about the configured 269 shasum suffix name and the digest(Checksum) callable. The 270 following configuration setting allows to configure the 271 size of the checksum: 272 273 shasum: 274 - size: 256 275 276 bundle: 277 - shasum_size: "256" 278 279 Instructs kiwi to use the provided shasum size. Supported 280 values are 256 (default) and 512. In case of an unsupported 281 value the default is used. A value from the bundle section 282 takes precedence over the global shasum size specified 283 in the shasum section for creating bundle results. If no 284 information for bundle results is specified, the global 285 shasum size or the default applies. 286 287 :param str source_filename: filename to calculate checksum for 288 :param str target_filename: filename to write checksum to 289 :param str default: default size set to 256 290 291 :rtype: ShasumT 292 """ 293 supported_shasums = { 294 '256': ShasumT( 295 suffix='.sha256', 296 digest=functools.partial( 297 Checksum(source_filename).sha256, target_filename 298 ) 299 ), 300 '512': ShasumT( 301 suffix='.sha512', 302 digest=functools.partial( 303 Checksum(source_filename).sha512, target_filename 304 ) 305 ) 306 } 307 shasum_size = self._get_attribute( 308 element='shasum', attribute='size' 309 ) 310 if bundle_lookup: 311 bundle_shasum_size = self._get_attribute( 312 element='bundle', attribute='shasum_size' 313 ) 314 if bundle_shasum_size: 315 shasum_size = bundle_shasum_size 316 if supported_shasums.get(shasum_size): 317 return supported_shasums[shasum_size] 318 return supported_shasums['256']
Return a ShasumT with information about the configured shasum suffix name and the digest(Checksum) callable. The following configuration setting allows to configure the size of the checksum:
shasum:
- size: 256
bundle:
- shasum_size: "256"
Instructs kiwi to use the provided shasum size. Supported values are 256 (default) and 512. In case of an unsupported value the default is used. A value from the bundle section takes precedence over the global shasum size specified in the shasum section for creating bundle results. If no information for bundle results is specified, the global shasum size or the default applies.
Parameters
- str source_filename: filename to calculate checksum for
- str target_filename: filename to write checksum to
- str default: default size set to 256
320 def get_xz_options(self) -> Optional[List[str]]: 321 """ 322 Return list of XZ compression options in: 323 324 xz: 325 - options: ... 326 327 if no configuration exists None is returned 328 329 :return: 330 Contains list of options 331 332 .. code:: python 333 334 ['--option=value'] 335 336 :rtype: list 337 """ 338 xz_options = self._get_attribute(element='xz', attribute='options') 339 return xz_options.split() if xz_options else None
Return list of XZ compression options in:
xz:
- options: ...
if no configuration exists None is returned
Returns
Contains list of options .. code:: python ['--option=value']
341 def get_container_compression(self) -> bool: 342 """ 343 Return compression for container images 344 345 container: 346 - compress: xz|none|true|false 347 348 if no or invalid configuration data is provided, the default 349 compression from the Defaults class is returned 350 351 :return: True or False 352 353 :rtype: bool 354 """ 355 container_compression = self._get_attribute( 356 element='container', attribute='compress' 357 ) 358 if container_compression is None: 359 return Defaults.get_container_compression() 360 elif 'xz' == container_compression or container_compression is True: 361 return True 362 elif 'none' == container_compression or container_compression is False: 363 return False 364 else: 365 log.warning( 366 'Skipping invalid container compression: {0}'.format( 367 container_compression 368 ) 369 ) 370 return Defaults.get_container_compression()
Return compression for container images
container:
- compress: xz|none|true|false
if no or invalid configuration data is provided, the default compression from the Defaults class is returned
Returns
True or False
372 def get_iso_tool_category(self) -> str: 373 """ 374 Return tool category which should be used to build iso images 375 376 iso: 377 - tool_category: xorriso 378 379 if no or invalid configuration exists the default tool category 380 from the Defaults class is returned 381 382 :return: A name 383 384 :rtype: str 385 """ 386 iso_tool_category = self._get_attribute( 387 element='iso', attribute='tool_category' 388 ) 389 if not iso_tool_category: 390 return Defaults.get_iso_tool_category() 391 elif 'xorriso' in iso_tool_category: 392 return iso_tool_category 393 else: 394 log.warning( 395 'Skipping invalid iso tool category: {0}'.format( 396 iso_tool_category 397 ) 398 ) 399 return Defaults.get_iso_tool_category()
Return tool category which should be used to build iso images
iso:
- tool_category: xorriso
if no or invalid configuration exists the default tool category from the Defaults class is returned
Returns
A name
401 def get_iso_media_tag_tool(self) -> Literal['checkmedia', 'isomd5sum']: 402 """ 403 Return media tag tool used to checksum iso images 404 405 iso: 406 - media_tag_tool: checkmedia 407 408 if no or invalid configuration exists the default media tagger 409 from the Defaults class is returned 410 411 :return: A name 412 413 :rtype: str 414 """ 415 iso_media_tag_tool = self._get_attribute( 416 element='iso', attribute='media_tag_tool' 417 ) 418 if not iso_media_tag_tool: 419 return Defaults.get_iso_media_tag_tool() 420 elif 'checkmedia' in iso_media_tag_tool: 421 return iso_media_tag_tool 422 elif 'isomd5sum' in iso_media_tag_tool: 423 return iso_media_tag_tool 424 else: 425 log.warning( 426 'Skipping invalid iso media tag tool: {0}'.format( 427 iso_media_tag_tool 428 ) 429 ) 430 return Defaults.get_iso_media_tag_tool()
Return media tag tool used to checksum iso images
iso:
- media_tag_tool: checkmedia
if no or invalid configuration exists the default media tagger from the Defaults class is returned
Returns
A name
432 def get_oci_archive_tool(self) -> str: 433 """ 434 Return OCI archive tool which should be used on creation of 435 container archives for OCI compliant images, e.g docker 436 437 oci: 438 - archive_tool: umoci 439 440 if no configuration exists the default tool from the 441 Defaults class is returned 442 443 :return: A name 444 445 :rtype: str 446 """ 447 oci_archive_tool = self._get_attribute( 448 element='oci', attribute='archive_tool' 449 ) 450 return oci_archive_tool or Defaults.get_oci_archive_tool()
Return OCI archive tool which should be used on creation of container archives for OCI compliant images, e.g docker
oci:
- archive_tool: umoci
if no configuration exists the default tool from the Defaults class is returned
Returns
A name
452 def get_mapper_tool(self) -> str: 453 """ 454 Return partition mapper tool 455 456 mapper: 457 - part_mapper: partx 458 459 if no configuration exists the default tool from the 460 Defaults class is returned 461 462 :return: A name 463 464 :rtype: str 465 """ 466 part_mapper_tool = self._get_attribute( 467 element='mapper', attribute='part_mapper' 468 ) 469 return part_mapper_tool or Defaults.get_part_mapper_tool()
Return partition mapper tool
mapper:
- part_mapper: partx
if no configuration exists the default tool from the Defaults class is returned
Returns
A name
471 def get_max_size_constraint(self) -> Optional[int]: 472 """ 473 Returns the maximum allowed size of the built image. The value is 474 returned in bytes and it is specified in build_constraints element 475 with the max_size attribute. The value can be specified in bytes or 476 it can be specified with m=MB or g=GB. 477 478 build_constraints: 479 - max_size: 700m 480 481 if no configuration exists None is returned 482 483 :return: byte value or None 484 485 :rtype: int 486 """ 487 max_size = self._get_attribute( 488 element='build_constraints', attribute='max_size' 489 ) 490 return StringToSize.to_bytes(max_size) if max_size else None
Returns the maximum allowed size of the built image. The value is returned in bytes and it is specified in build_constraints element with the max_size attribute. The value can be specified in bytes or it can be specified with m=MB or g=GB.
build_constraints:
- max_size: 700m
if no configuration exists None is returned
Returns
byte value or None
492 def get_disabled_runtime_checks(self) -> List[str]: 493 """ 494 Returns disabled runtime checks. Checks can be disabled with: 495 496 runtime_checks: 497 - disable: check_container_tool_chain_installed 498 499 if the provided string does not match any RuntimeChecker method it is 500 just ignored. 501 """ 502 disabled_checks = self._get_attribute( 503 element='runtime_checks', attribute='disable' 504 ) or [] 505 for check in disabled_checks: 506 log.warning(f'Runtime check: {check}: disabled') 507 return disabled_checks
Returns disabled runtime checks. Checks can be disabled with:
runtime_checks: - disable: check_container_tool_chain_installed
if the provided string does not match any RuntimeChecker method it is just ignored.