| Viewing file:  cc_apk_configure.py (9.35 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# Copyright (c) 2020 Dermot Bradley#
 # Author: Dermot Bradley <dermot_bradley@yahoo.com>
 #
 # This file is part of cloud-init. See LICENSE file for license information.
 
 """Apk Configure: Configures apk repositories file."""
 
 from textwrap import dedent
 
 from cloudinit import log as logging
 from cloudinit import temp_utils
 from cloudinit import templater
 from cloudinit import util
 from cloudinit.config.schema import (
 get_schema_doc, validate_cloudconfig_schema)
 from cloudinit.settings import PER_INSTANCE
 
 LOG = logging.getLogger(__name__)
 
 
 # If no mirror is specified then use this one
 DEFAULT_MIRROR = "https://alpine.global.ssl.fastly.net/alpine"
 
 
 REPOSITORIES_TEMPLATE = """\
 ## template:jinja
 #
 # Created by cloud-init
 #
 # This file is written on first boot of an instance
 #
 
 {{ alpine_baseurl }}/{{ alpine_version }}/main
 {% if community_enabled -%}
 {{ alpine_baseurl }}/{{ alpine_version }}/community
 {% endif -%}
 {% if testing_enabled -%}
 {% if alpine_version != 'edge' %}
 #
 # Testing - using with non-Edge installation may cause problems!
 #
 {% endif %}
 {{ alpine_baseurl }}/edge/testing
 {% endif %}
 {% if local_repo != '' %}
 
 #
 # Local repo
 #
 {{ local_repo }}/{{ alpine_version }}
 {% endif %}
 
 """
 
 
 frequency = PER_INSTANCE
 distros = ['alpine']
 schema = {
 'id': 'cc_apk_configure',
 'name': 'APK Configure',
 'title': 'Configure apk repositories file',
 'description': dedent("""\
 This module handles configuration of the /etc/apk/repositories file.
 
 .. note::
 To ensure that apk configuration is valid yaml, any strings
 containing special characters, especially ``:`` should be quoted.
 """),
 'distros': distros,
 'examples': [
 dedent("""\
 # Keep the existing /etc/apk/repositories file unaltered.
 apk_repos:
 preserve_repositories: true
 """),
 dedent("""\
 # Create repositories file for Alpine v3.12 main and community
 # using default mirror site.
 apk_repos:
 alpine_repo:
 community_enabled: true
 version: 'v3.12'
 """),
 dedent("""\
 # Create repositories file for Alpine Edge main, community, and
 # testing using a specified mirror site and also a local repo.
 apk_repos:
 alpine_repo:
 base_url: 'https://some-alpine-mirror/alpine'
 community_enabled: true
 testing_enabled: true
 version: 'edge'
 local_repo_base_url: 'https://my-local-server/local-alpine'
 """),
 ],
 'frequency': frequency,
 'type': 'object',
 'properties': {
 'apk_repos': {
 'type': 'object',
 'properties': {
 'preserve_repositories': {
 'type': 'boolean',
 'default': False,
 'description': dedent("""\
 By default, cloud-init will generate a new repositories
 file ``/etc/apk/repositories`` based on any valid
 configuration settings specified within a apk_repos
 section of cloud config. To disable this behavior and
 preserve the repositories file from the pristine image,
 set ``preserve_repositories`` to ``true``.
 
 The ``preserve_repositories`` option overrides
 all other config keys that would alter
 ``/etc/apk/repositories``.
 """)
 },
 'alpine_repo': {
 'type': ['object', 'null'],
 'properties': {
 'base_url': {
 'type': 'string',
 'default': DEFAULT_MIRROR,
 'description': dedent("""\
 The base URL of an Alpine repository, or
 mirror, to download official packages from.
 If not specified then it defaults to ``{}``
 """.format(DEFAULT_MIRROR))
 },
 'community_enabled': {
 'type': 'boolean',
 'default': False,
 'description': dedent("""\
 Whether to add the Community repo to the
 repositories file. By default the Community
 repo is not included.
 """)
 },
 'testing_enabled': {
 'type': 'boolean',
 'default': False,
 'description': dedent("""\
 Whether to add the Testing repo to the
 repositories file. By default the Testing
 repo is not included. It is only recommended
 to use the Testing repo on a machine running
 the ``Edge`` version of Alpine as packages
 installed from Testing may have dependancies
 that conflict with those in non-Edge Main or
 Community repos."
 """)
 },
 'version': {
 'type': 'string',
 'description': dedent("""\
 The Alpine version to use (e.g. ``v3.12`` or
 ``edge``)
 """)
 },
 },
 'required': ['version'],
 'minProperties': 1,
 'additionalProperties': False,
 },
 'local_repo_base_url': {
 'type': 'string',
 'description': dedent("""\
 The base URL of an Alpine repository containing
 unofficial packages
 """)
 }
 },
 'required': [],
 'minProperties': 1,  # Either preserve_repositories or alpine_repo
 'additionalProperties': False,
 }
 }
 }
 
 __doc__ = get_schema_doc(schema)
 
 
 def handle(name, cfg, cloud, log, _args):
 """
 Call to handle apk_repos sections in cloud-config file.
 
 @param name: The module name "apk-configure" from cloud.cfg
 @param cfg: A nested dict containing the entire cloud config contents.
 @param cloud: The CloudInit object in use.
 @param log: Pre-initialized Python logger object to use for logging.
 @param _args: Any module arguments from cloud.cfg
 """
 
 # If there is no "apk_repos" section in the configuration
 # then do nothing.
 apk_section = cfg.get('apk_repos')
 if not apk_section:
 LOG.debug(("Skipping module named %s,"
 " no 'apk_repos' section found"), name)
 return
 
 validate_cloudconfig_schema(cfg, schema)
 
 # If "preserve_repositories" is explicitly set to True in
 # the configuration do nothing.
 if util.get_cfg_option_bool(apk_section, 'preserve_repositories', False):
 LOG.debug(("Skipping module named %s,"
 " 'preserve_repositories' is set"), name)
 return
 
 # If there is no "alpine_repo" subsection of "apk_repos" present in the
 # configuration then do nothing, as at least "version" is required to
 # create valid repositories entries.
 alpine_repo = apk_section.get('alpine_repo')
 if not alpine_repo:
 LOG.debug(("Skipping module named %s,"
 " no 'alpine_repo' configuration found"), name)
 return
 
 # If there is no "version" value present in configuration then do nothing.
 alpine_version = alpine_repo.get('version')
 if not alpine_version:
 LOG.debug(("Skipping module named %s,"
 " 'version' not specified in alpine_repo"), name)
 return
 
 local_repo = apk_section.get('local_repo_base_url', '')
 
 _write_repositories_file(alpine_repo, alpine_version, local_repo)
 
 
 def _write_repositories_file(alpine_repo, alpine_version, local_repo):
 """
 Write the /etc/apk/repositories file with the specified entries.
 
 @param alpine_repo: A nested dict of the alpine_repo configuration.
 @param alpine_version: A string of the Alpine version to use.
 @param local_repo: A string containing the base URL of a local repo.
 """
 
 repo_file = '/etc/apk/repositories'
 
 alpine_baseurl = alpine_repo.get('base_url', DEFAULT_MIRROR)
 
 params = {'alpine_baseurl': alpine_baseurl,
 'alpine_version': alpine_version,
 'community_enabled': alpine_repo.get('community_enabled'),
 'testing_enabled': alpine_repo.get('testing_enabled'),
 'local_repo': local_repo}
 
 tfile = temp_utils.mkstemp(prefix='template_name-', suffix=".tmpl")
 template_fn = tfile[1]  # Filepath is second item in tuple
 util.write_file(template_fn, content=REPOSITORIES_TEMPLATE)
 
 LOG.debug('Generating Alpine repository configuration file: %s',
 repo_file)
 templater.render_to_file(template_fn, repo_file, params)
 # Clean up temporary template
 util.del_file(template_fn)
 
 
 # vi: ts=4 expandtab
 
 |