Add local volume provisioner chart
Some applications require perisitant volumes to be stored on the hosts where they running, usually its done via kubernetes PV. One of PV implementations is local-volume-provisioner [0] This patch adds helm chart to deploy LVP. Since LVP creates a volumes for each mountpoint, helm chart provides a script to create mountpoints in the directory, which later exposed to kubernetes as individual volumes. Change-Id: I3f61088ddcbd0a83a729eb940cbf9b2bf1e65894
This commit is contained in:
parent
2acad7bad8
commit
db6c9ac78c
24
local-volume-provisioner/Chart.yaml
Normal file
24
local-volume-provisioner/Chart.yaml
Normal file
@ -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
|
||||
...
|
18
local-volume-provisioner/requirements.yaml
Normal file
18
local-volume-provisioner/requirements.yaml
Normal file
@ -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"
|
||||
...
|
377
local-volume-provisioner/templates/bin/_fakemount.py.tpl
Normal file
377
local-volume-provisioner/templates/bin/_fakemount.py.tpl
Normal file
@ -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)
|
58
local-volume-provisioner/templates/configmap-bin.yaml
Normal file
58
local-volume-provisioner/templates/configmap-bin.yaml
Normal file
@ -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 }}
|
33
local-volume-provisioner/templates/configmap-etc.yaml
Normal file
33
local-volume-provisioner/templates/configmap-etc.yaml
Normal file
@ -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 }}
|
212
local-volume-provisioner/templates/daemonset-lvp.yaml
Normal file
212
local-volume-provisioner/templates/daemonset-lvp.yaml
Normal file
@ -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 }}
|
18
local-volume-provisioner/templates/job-image-repo-sync.yaml
Normal file
18
local-volume-provisioner/templates/job-image-repo-sync.yaml
Normal file
@ -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 }}
|
17
local-volume-provisioner/templates/secret-registry.yaml
Normal file
17
local-volume-provisioner/templates/secret-registry.yaml
Normal file
@ -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 }}
|
27
local-volume-provisioner/templates/storageclasses.yaml
Normal file
27
local-volume-provisioner/templates/storageclasses.yaml
Normal file
@ -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 }}
|
153
local-volume-provisioner/values.yaml
Normal file
153
local-volume-provisioner/values.yaml
Normal file
@ -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
|
||||
...
|
4
releasenotes/notes/local-volume-provisioner.yaml
Normal file
4
releasenotes/notes/local-volume-provisioner.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
local-volume-provisioner:
|
||||
- 0.1.0 Initial Chart
|
||||
...
|
Loading…
Reference in New Issue
Block a user