diff --git a/local-volume-provisioner/Chart.yaml b/local-volume-provisioner/Chart.yaml new file mode 100644 index 0000000000..a33684e87f --- /dev/null +++ b/local-volume-provisioner/Chart.yaml @@ -0,0 +1,24 @@ +# 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. + +--- +apiVersion: v1 +appVersion: v1.0.0 +description: OpenStack-Helm local-volume-provisioner +name: local-volume-provisioner +version: 0.1.0 +home: https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner +sources: + - https://opendev.org/openstack/openstack-helm +maintainers: + - name: OpenStack-Helm Authors +... diff --git a/local-volume-provisioner/requirements.yaml b/local-volume-provisioner/requirements.yaml new file mode 100644 index 0000000000..84f0affae0 --- /dev/null +++ b/local-volume-provisioner/requirements.yaml @@ -0,0 +1,18 @@ +# 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. + +--- +dependencies: + - name: helm-toolkit + repository: file://../helm-toolkit + version: ">= 0.1.0" +... diff --git a/local-volume-provisioner/templates/bin/_fakemount.py.tpl b/local-volume-provisioner/templates/bin/_fakemount.py.tpl new file mode 100644 index 0000000000..e9a937f4e2 --- /dev/null +++ b/local-volume-provisioner/templates/bin/_fakemount.py.tpl @@ -0,0 +1,377 @@ +#!/usr/bin/env python3 +# +# Copyright 2019 Mirantis, 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. +"""Fakemount python module +The module is aimed to crate fake mountpoints (--bind). +Example: + python3 fakemount --config-file '/root/mymount.yml' +Attributes: + config-file - file path to config file that contains fake mounts. +""" +__version__ = "1.0" +import argparse +import logging +import os +import re +import subprocess +import sys +from collections import defaultdict +import yaml +logging.basicConfig(stream=sys.stdout, level=logging.INFO) +LOG = logging.getLogger(__name__) +MOUNT_BIN = "/bin/mount" +###Fork https://github.com/b10011/pyfstab/ ##################################### +# Latest commit 828540d +class InvalidEntry(Exception): + """ + Raised when a string cannot be generated because of the Entry is invalid. + """ +class InvalidFstabLine(Exception): + """ + Raised when a line is invalid in fstab. This doesn't just mean that the + Entry will be invalid but also that the system can not process the fstab + file fully either. + """ +class Entry: + """ + Handles parsing and formatting fstab line entries. + :var device: + (str or None) - + Fstab device (1st parameter in the fstab entry) + :var dir: + (str or None) - + Fstab device (2nd parameter in the fstab entry) + :var type: + (str or None) - + Fstab device (3rd parameter in the fstab entry) + :var options: + (str or None) - + Fstab device (4th parameter in the fstab entry) + :var dump: + (int or None) - + Fstab device (5th parameter in the fstab entry) + :var fsck: + (int or None) - + Fstab device (6th parameter in the fstab entry) + :var valid: + (bool) - + Whether the Entry is valid or not. Can be checked with "if entry:". + """ + def __init__( + self, + _device=None, + _dir=None, + _type=None, + _options=None, + _dump=None, + _fsck=None, + ): + """ + :param _device: Fstab device (1st parameter in the fstab entry) + :type _device: str + :param _dir: Fstab device (2nd parameter in the fstab entry) + :type _dir: str + :param _type: Fstab device (3rd parameter in the fstab entry) + :type _type: str + :param _options: Fstab device (4th parameter in the fstab entry) + :type _options: str + :param _dump: Fstab device (5th parameter in the fstab entry) + :type _dump: int + :param _fsck: Fstab device (6th parameter in the fstab entry) + :type _fsck: int + """ + self.device = _device + self.dir = _dir + self.type = _type + self.options = _options + self.dump = _dump + self.fsck = _fsck + self.valid = True + self.valid &= self.device is not None + self.valid &= self.dir is not None + self.valid &= self.type is not None + self.valid &= self.options is not None + self.valid &= self.dump is not None + self.valid &= self.fsck is not None + def read_string(self, line): + """ + Parses an entry from a string + :param line: Fstab entry line. + :type line: str + :return: self + :rtype: Entry + :raises InvalidEntry: If the data in the string cannot be parsed. + """ + line = line.strip() + if line and not line[0] == "#": + parts = re.split(r"\s+", line) + if len(parts) == 6: + [_device, _dir, _type, _options, _dump, _fsck] = parts + _dump = int(_dump) + _fsck = int(_fsck) + self.device = _device + self.dir = _dir + self.type = _type + self.options = _options + self.dump = _dump + self.fsck = _fsck + self.valid = True + return self + else: + raise InvalidFstabLine() + self.device = None + self.dir = None + self.type = None + self.options = None + self.dump = None + self.fsck = None + self.valid = False + raise InvalidEntry("Entry cannot be parsed") + def write_string(self): + """ + Formats the Entry into fstab entry line. + :return: Fstab entry line. + :rtype: str + :raises InvalidEntry: + A string cannot be generated because the entry is invalid. + """ + if self: + return "{} {} {} {} {} {}".format( + self.device, + self.dir, + self.type, + self.options, + self.dump, + self.fsck, + ) + else: + raise InvalidEntry("Entry cannot be formatted") + def __bool__(self): + return self.valid + def __str__(self): + return self.write_string() + def __repr__(self): + try: + return "<Entry {}>".format(str(self)) + except InvalidEntry: + return "<Entry Invalid>" +class Fstab: + """ + Handles reading, parsing, formatting and writing of fstab files. + :var entries: + (list[Entry]) - + List of entries. + When writing to a file, entries are listed from this list. + :var entries_by_device: + (dict[str, list[Entry]]) - + Fstab entries by device. + :var entry_by_dir: + (dict[str, Entry]) - + Fstab entry by directory. + :var entries_by_type: + (dict[str, list[Entry]]) - + Fstab entries by type. + """ + def __init__(self): + self.entries = [] + # A single device can have multiple mountpoints + self.entries_by_device = defaultdict(list) + # If multiple devices have same mountpoint, only the last entry in the + # fstab file is taken into consideration + self.entry_by_dir = dict() + # And the most obvious one, many entries can have mountpoints of same + # type + self.entries_by_type = defaultdict(list) + def read_string(self, data, only_valid=False): + """ + Parses entries from a data string + :param data: Contents of the fstab file + :type data: str + :param only_valid: + Skip the entries that do not actually mount. For example, if device + A is mounted to directory X and later device B is mounted to + directory X, the A mount to X is undone by the system. + :type only_valid: bool + :return: self + :rtype: Fstab + """ + for line in reversed(data.splitlines()): + try: + entry = Entry().read_string(line) + if entry and ( + not only_valid or entry.dir not in self.entry_by_dir + ): + self.entries.insert(0, entry) + self.entries_by_device[entry.device].insert(0, entry) + self.entry_by_dir[entry.dir] = entry + self.entries_by_type[entry.type].insert(0, entry) + except InvalidEntry: + pass + return self + def write_string(self): + """ + Formats entries into a string. + :return: Formatted fstab file. + :rtype: str + :raises InvalidEntry: + A string cannot be generated because one of the entries is invalid. + """ + return "\n".join(str(entry) for entry in self.entries) + def read_file(self, handle, only_valid=False): + """ + Parses entries from a file + :param handle: File handle + :type handle: file + :param only_valid: + Skip the entries that do not actually mount. For example, if device + A is mounted to directory X and later device B is mounted to + directory X, the A mount to X is undone by the system. + :type only_valid: bool + :return: self + :rtype: Fstab + """ + self.read_string(handle.read(), only_valid) + return self + def write_file(self, handle): + """ + Parses entries in data string + :param path: File handle + :type path: file + :return: self + :rtype: Fstab + """ + handle.write(str(self)) + return self + def __bool__(self): + return len(self.entries) > 0 + def __str__(self): + return self.write_string() + def __repr__(self): + res = "<Fstab [{} entries]".format(len(self.entries)) + if self.entries: + res += "\n" + for entry in self.entries: + res += " {}\n".format(entry) + res += ">" + return res +###End Fork https://github.com/b10011/pyfstab/ ################################# +def fstab_bindmount(src, mountpoint, fstab_path="/mnt/host/fstab", opts=None): + if opts is None: + opts = ["bind"] + mountpoint = os.path.normpath(mountpoint.strip()) + with open(fstab_path, "r") as f: + fstab = Fstab().read_file(f) + if mountpoint in fstab.entry_by_dir: + LOG.info(f'Mount point {mountpoint} already defined in {fstab_path}') + return + fstab.entries.append(Entry(src, mountpoint, "none", ",".join(opts), 0, 0)) + str_fstab = str(fstab) + LOG.info(f'Attempt to overwrite file:{fstab_path}, with data:\n' + f'{str_fstab}') + with open(fstab_path, "w") as f: + f.write(str_fstab) +def get_volumes(mount_point, i): + vol_template = "vol%d%%d" % i + volumes = mount_point.get("mounts") + if volumes is not None: + return volumes + return [vol_template % vol_number for vol_number in + range(mount_point["volPerNode"])] +def ensure_directories_exists(storage_class): + target_root = storage_class.get("mountDir", storage_class["hostDir"]) + for i, bind_mount in enumerate(storage_class["bindMounts"]): + for vol_name in get_volumes(bind_mount, i): + source = os.path.normpath(f"{bind_mount['srcRoot']}/{vol_name}") + target = os.path.normpath(f"{target_root}/{vol_name}") + os.makedirs(target, exist_ok=True) + os.makedirs(source, exist_ok=True) +def is_mount(directory): + # Do not use os.path.ismount due to bug + # https://bugs.python.org/issue29707 + directory = os.path.normpath(directory.strip()) + with open("/proc/mounts") as f: + for line in f.readlines(): + if line.split(" ")[1] == directory: + return True +def mount_directories(storage_class): + failed_mounts = [] + target_root = storage_class.get("mountDir", storage_class["hostDir"]) + additional_opts = storage_class.get("additionalMountOptions", []) + opts = ["bind"] + additional_opts + for i, bind_mount in enumerate(storage_class["bindMounts"]): + for vol_name in get_volumes(bind_mount, i): + source = os.path.normpath(f"{bind_mount['srcRoot']}/{vol_name}") + target = os.path.normpath(f"{target_root}/{vol_name}") + LOG.info(f"Trying to mount {source} to {target}") + if is_mount(target): + LOG.info( + f"The directory {target} already mounted, skipping it...") + else: + cmd = [MOUNT_BIN, "-o", ",".join(opts), source, target] + LOG.info(f"Running {cmd}") + obj = None + try: + obj = subprocess.run( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + obj.check_returncode() + except Exception as e: + LOG.exception( + f"Failed to mount {source} {target}\n" + f"stdout: {obj.stdout}\n" + f"stderr: {obj.stderr}" + ) + failed_mounts.append((source, target)) + else: + LOG.info(f"Successfully mount {source} {target}") + fstab_bindmount(source, target, opts=opts) + if failed_mounts: + raise Exception(f"Failed to mount some directories: {failed_mounts}") +def main(): + parser = argparse.ArgumentParser( + description="Create fake mountpotins with specified directories." + ) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument( + "--config-file", help="Path to file with image layout", + ) + parser.add_argument( + "--create-only", + help="Ensure target directories exists.", + dest="create_only", + action="store_true", + ) + parser.set_defaults(create_only=False) + args = parser.parse_args() + with open(args.config_file) as f: + data = yaml.safe_load(f) + if data is None: + LOG.exception("Invalid data supplied from the config file.") + raise Exception + classes_data = data.get("classes", []) + if isinstance(classes_data, list): + for storage_class in classes_data: + ensure_directories_exists(storage_class) + if not args.create_only: + for storage_class in classes_data: + mount_directories(storage_class) +if __name__ == "__main__": + try: + main() + except Exception as e: + LOG.exception("Can't create volume mounts.") + sys.exit(1) diff --git a/local-volume-provisioner/templates/configmap-bin.yaml b/local-volume-provisioner/templates/configmap-bin.yaml new file mode 100644 index 0000000000..5160cf88fb --- /dev/null +++ b/local-volume-provisioner/templates/configmap-bin.yaml @@ -0,0 +1,58 @@ +{{/* +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. +*/}} + +{{- define "lvp.configmap.bin" }} +{{- $configMapName := index . 0 }} +{{- $envAll := index . 1 }} +{{- with $envAll }} + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $configMapName }} +data: +{{- if .Values.images.local_registry.active }} + image-repo-sync.sh: | +{{- include "helm-toolkit.scripts.image_repo_sync" . | indent 4 }} +{{- end }} + fakemount.py: | +{{ tuple "bin/_fakemount.py.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + storageClassMap: | + {{- range $classConfig := $envAll.Values.conf.fake_mounts.classes }} + {{ $classConfig.name }}: + hostDir: {{ $classConfig.hostDir }} + mountDir: {{ $classConfig.mountDir | default $classConfig.hostDir }} + {{- if $classConfig.blockCleanerCommand }} + blockCleanerCommand: + {{- range $val := $classConfig.blockCleanerCommand }} + - {{ $val | quote }} + {{- end}} + {{- end }} + {{- if $classConfig.volumeMode }} + volumeMode: {{ $classConfig.volumeMode }} + {{- end }} + {{- if $classConfig.fsType }} + fsType: {{ $classConfig.fsType }} + {{- end }} + {{- if $classConfig.namePattern }} + namePattern: {{ $classConfig.namePattern | quote }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} + +{{- if .Values.manifests.configmap_bin }} +{{- list "local-volume-provisioner-bin" . | include "lvp.configmap.bin" }} +{{- end }} diff --git a/local-volume-provisioner/templates/configmap-etc.yaml b/local-volume-provisioner/templates/configmap-etc.yaml new file mode 100644 index 0000000000..4684854852 --- /dev/null +++ b/local-volume-provisioner/templates/configmap-etc.yaml @@ -0,0 +1,33 @@ +{{/* +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. +*/}} + +{{- define "lvp.configmap.etc" }} +{{- $configMapName := index . 0 }} +{{- $envAll := index . 1 }} +{{- with $envAll }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $configMapName }} +type: Opaque +data: + fake_mounts.conf: {{ $envAll.Values.conf.fake_mounts | toJson | b64enc }} +{{- end }} +{{- end }} + +{{- if .Values.manifests.configmap_etc }} +{{- list "local-volume-provisioner-etc" . | include "lvp.configmap.etc" }} +{{- end }} diff --git a/local-volume-provisioner/templates/daemonset-lvp.yaml b/local-volume-provisioner/templates/daemonset-lvp.yaml new file mode 100644 index 0000000000..0c8da93e98 --- /dev/null +++ b/local-volume-provisioner/templates/daemonset-lvp.yaml @@ -0,0 +1,212 @@ +{{/* +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. +*/}} + +{{- define "lvp.daemonset" }} +{{- $daemonset := index . 0 }} +{{- $configMapName := index . 1 }} +{{- $serviceAccountName := index . 2 }} +{{- $envAll := index . 3 }} + +{{- with $envAll }} + +{{- $mounts_lvp := $envAll.Values.pod.mounts.local_volume_provisioner.lvp }} +{{- $mounts_lvp_init := $envAll.Values.pod.mounts.local_volume_provisioner.init_container }} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: local-volume-provisioner + annotations: + {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }} + labels: +{{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + selector: + matchLabels: +{{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll $daemonset | include "helm-toolkit.snippets.kubernetes_upgrades_daemonset" | indent 2 }} + template: + metadata: + labels: +{{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + annotations: +{{- dict "envAll" $envAll "podName" "local-volume-provisioner" "containerNames" (list "lvp") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }} +{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }} + configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }} + configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }} + spec: +{{ dict "envAll" $envAll "application" "local-volume-provisioner" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }} + serviceAccountName: {{ $serviceAccountName }} + nodeSelector: + {{ $envAll.Values.labels.local_volume_provisioner.node_selector_key }}: {{ $envAll.Values.labels.local_volume_provisioner.node_selector_value }} + initContainers: + - name: init-mounts +{{ tuple $envAll "local_volume_provisioner_mounts" | include "helm-toolkit.snippets.image" | indent 10 }} +{{ dict "envAll" $envAll "application" "local_volume_provisioner" "container" "init_mounts" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }} + terminationMessagePath: /var/log/termination-log + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PATH + value: /var/lib/openstack/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/ + command: + - /tmp/fakemount.py + - --config-file + - /etc/provisioner/fake_mounts.conf + volumeMounts: + - name: fstab + mountPath: /mnt/host/fstab + - name: local-volume-provisioner-etc + mountPath: /etc/provisioner/fake_mounts.conf + subPath: fake_mounts.conf + readOnly: true + - name: local-volume-provisioner-bin + mountPath: /tmp/fakemount.py + subPath: fakemount.py + readOnly: true + {{- range $classConfig := $envAll.Values.conf.fake_mounts.classes }} + {{- range $bindMount := $classConfig.bindMounts }} + - mountPath: {{ $bindMount.srcRoot }} + mountPropagation: Bidirectional + name: {{ replace "/" "" $bindMount.srcRoot }} + {{- end }} + - mountPath: {{ if $classConfig.mountDir }} {{- $classConfig.mountDir -}} {{ else }} {{- $classConfig.hostDir -}} {{ end }} + mountPropagation: Bidirectional + name: {{ $classConfig.name }} + {{- end }} + - mountPath: /run + name: run + containers: + - name: lvp +{{ tuple $envAll "local_volume_provisioner" | include "helm-toolkit.snippets.image" | indent 10 }} +{{ tuple $envAll $envAll.Values.pod.resources.local_volume_provisioner | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} +{{ dict "envAll" $envAll "application" "local_volume_provisioner" "container" "lvp" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }} + env: + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + command: + - /local-provisioner + volumeMounts: + - name: local-volume-provisioner-bin + mountPath: /etc/provisioner/config/storageClassMap + subPath: storageClassMap + readOnly: true + - name: dev + mountPath: /dev + {{- range $classConfig := $envAll.Values.conf.fake_mounts.classes }} + - name: {{ $classConfig.name }} + mountPath: {{ $classConfig.mountDir | default $classConfig.hostDir }} + mountPropagation: HostToContainer + {{- end }} + volumes: + - name: fstab + hostPath: + type: File + path: /etc/fstab + - name: local-volume-provisioner-bin + configMap: + name: local-volume-provisioner-bin + defaultMode: 0555 + - name: local-volume-provisioner-etc + secret: + secretName: {{ $configMapName }} + defaultMode: 0444 + - name: run + hostPath: + path: /run + - name: dev + hostPath: + path: /dev + {{- range $classConfig := $envAll.Values.conf.fake_mounts.classes }} + {{- range $bindMount := $classConfig.bindMounts }} + - name: {{ replace "/" "" $bindMount.srcRoot }} + hostPath: + path: {{ $bindMount.srcRoot }} + type: "" + {{- end }} + {{- end }} + {{- range $classConfig := $envAll.Values.conf.fake_mounts.classes }} + - name: {{ $classConfig.name }} + hostPath: + path: {{ $classConfig.hostDir }} + {{- end }} +{{ if $mounts_lvp.volumes }}{{ toYaml $mounts_lvp.volumes | indent 8 }}{{ end }} +{{- end }} +{{- end }} + +{{- if .Values.manifests.daemonset_local_volume_provisioner }} + +{{- $envAll := . }} +{{- $daemonset := "local_volume_provisioner" }} +{{- $configMapName := "local_volume_provisioner-etc" }} +{{- $serviceAccountName := "local-volume-provisioner" }} + +{{ tuple $envAll "lvp" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ $serviceAccountName }}-nodes +rules: +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ $serviceAccountName }}-nodes +subjects: +- kind: ServiceAccount + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ $serviceAccountName }}-nodes + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ $serviceAccountName }}-cluter-admin +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} + +{{- $daemonset_yaml := list $daemonset $configMapName $serviceAccountName . | include "lvp.daemonset" | toString | fromYaml }} +{{- $configmap_yaml := "lvp.configmap.etc" }} +{{- list $daemonset $daemonset_yaml $configmap_yaml $configMapName . | include "helm-toolkit.utils.daemonset_overrides" }} + +{{- end }} diff --git a/local-volume-provisioner/templates/job-image-repo-sync.yaml b/local-volume-provisioner/templates/job-image-repo-sync.yaml new file mode 100644 index 0000000000..1aab34c9c3 --- /dev/null +++ b/local-volume-provisioner/templates/job-image-repo-sync.yaml @@ -0,0 +1,18 @@ +{{/* +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. +*/}} + +{{- if and .Values.manifests.job_image_repo_sync .Values.images.local_registry.active }} +{{- $imageRepoSyncJob := dict "envAll" . "serviceName" "local-volume-provisioner" -}} +{{ $imageRepoSyncJob | include "helm-toolkit.manifests.job_image_repo_sync" }} +{{- end }} diff --git a/local-volume-provisioner/templates/secret-registry.yaml b/local-volume-provisioner/templates/secret-registry.yaml new file mode 100644 index 0000000000..da979b3223 --- /dev/null +++ b/local-volume-provisioner/templates/secret-registry.yaml @@ -0,0 +1,17 @@ +{{/* +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. +*/}} + +{{- if and .Values.manifests.secret_registry .Values.endpoints.oci_image_registry.auth.enabled }} +{{ include "helm-toolkit.manifests.secret_registry" ( dict "envAll" . "registryUser" .Chart.Name ) }} +{{- end }} diff --git a/local-volume-provisioner/templates/storageclasses.yaml b/local-volume-provisioner/templates/storageclasses.yaml new file mode 100644 index 0000000000..33b573c9eb --- /dev/null +++ b/local-volume-provisioner/templates/storageclasses.yaml @@ -0,0 +1,27 @@ +{{- if .Values.manifests.storageclass }} +{{- $envAll := . }} +{{- range $val := $envAll.Values.conf.fake_mounts.classes }} +{{- if $val.storageClass }} +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: {{ $val.name }} + {{- if kindIs "map" $val.storageClass }} + {{- if $val.storageClass.isDefaultClass }} + annotations: + storageclass.kubernetes.io/is-default-class: "true" + {{- end }} + {{- end }} + labels: +{{ tuple $envAll $envAll.Chart.Name "storageclass" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer +{{- if kindIs "map" $val.storageClass }} +reclaimPolicy: {{ $val.storageClass.reclaimPolicy | default "Delete" }} +{{- else }} +reclaimPolicy: Delete +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/local-volume-provisioner/values.yaml b/local-volume-provisioner/values.yaml new file mode 100644 index 0000000000..4cbb5db223 --- /dev/null +++ b/local-volume-provisioner/values.yaml @@ -0,0 +1,153 @@ +# 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. + +# Default values for local-volume-provisioner. +# This is a YAML-formatted file. +# Declare name/value pairs to be passed into your templates. +# name: value + +--- +release_group: null + +labels: + local_volume_provisioner: + node_selector_key: openstack-compute-node + node_selector_value: enabled + +images: + tags: + local_volume_provisioner: mirantis.azurecr.io/bm/external/local-volume-provisioner:v2.4.0 + dep_check: quay.io/airshipit/kubernetes-entrypoint:latest-ubuntu_focal + image_repo_sync: docker.io/library/docker:17.07.0 + local_volume_provisioner_mounts: mirantis.azurecr.io/openstack/openstack-controller:0.1.1 + pull_policy: "IfNotPresent" + local_registry: + active: false + exclude: + - dep_check + - image_repo_sync + +dependencies: + static: {} + dynamic: {} + +endpoints: + cluster_domain_suffix: cluster.local + local_image_registry: + name: docker-registry + namespace: docker-registry + hosts: + default: localhost + internal: docker-registry + node: localhost + host_fqdn_override: + default: null + port: + registry: + node: 5000 + oci_image_registry: + name: oci-image-registry + namespace: oci-image-registry + auth: + enabled: false + local_volume_provisioner: + username: local_volume_provisioner + password: password + hosts: + default: localhost + host_fqdn_override: + default: null + port: + registry: + default: null + +conf: + fake_mounts: + classes: + - bindMounts: + - mounts: + - vol1 + - vol2 + - vol3 + - vol4 + - vol5 + - vol6 + - vol7 + - vol8 + - vol9 + - vol10 + - vol11 + - vol12 + - vol13 + - vol14 + - vol15 + srcRoot: /var/lib/local-volume-provisioner + hostDir: /mnt/local-volume-provisioner + mountDir: /mnt/local-volume-provisioner + name: lvp-fake-root + storageClass: true + volumeMode: Filesystem +pod: + security_context: + local_volume_provisioner: + pod: + runAsUser: 0 + container: + lvp: + privileged: true + readOnlyRootFilesystem: true + init_mounts: + privileged: true + readOnlyRootFilesystem: true + dns_policy: "ClusterFirstWithHostNet" + mounts: + local_volume_provisioner: + init_container: null + lvp: null + lifecycle: + upgrades: + daemonsets: + pod_replacement_strategy: RollingUpdate + local_volume_provisioner: + enabled: true + min_ready_seconds: 0 + max_unavailable: 1 + resources: + enabled: false + local_volume_provisioner: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + jobs: + image_repo_sync: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + +manifests: + configmap_bin: true + configmap_etc: true + daemonset_local_volume_provisioner: true + job_image_repo_sync: true + secret_registry: true + storageclass: true + +secrets: + oci_image_registry: + local_volume_provisioner: local-volume-provisioner-oci-image-registry-key +... diff --git a/releasenotes/notes/local-volume-provisioner.yaml b/releasenotes/notes/local-volume-provisioner.yaml new file mode 100644 index 0000000000..ccf1a1731b --- /dev/null +++ b/releasenotes/notes/local-volume-provisioner.yaml @@ -0,0 +1,4 @@ +--- +local-volume-provisioner: + - 0.1.0 Initial Chart +...