Example - ConfigMap
Introduction
There are many Kubernetes installations either as a manifest or a Helm chart that after undeployment leave ConfigMap
behind.
The below Cleaner instance finds all the ConfigMaps
instances in all the namespaces which are orphaned (namespaces starting with kube
are excluded)
Orphaned ConfigMap
By orphaned we refer to a ConfigMap that is not used by:
- Pod through volumes (pod.spec.volumes)
- Pod through environment variables (pod.spec.containers.env and pod.spec.containers.envFrom)
Example - Cleaner Instance
---
apiVersion: apps.projectsveltos.io/v1alpha1
kind: Cleaner
metadata:
name: unused-configmaps
spec:
schedule: "* 0 * * *"
action: Delete
resourcePolicySet:
resourceSelectors:
- kind: Pod
group: ""
version: v1
- kind: ConfigMap
group: ""
version: v1
aggregatedSelection: |
function skipNamespace(namespace)
return string.match(namespace, '^kube')
end
function getKey(namespace, name)
return namespace .. ":" .. name
end
function configMapsUsedByPods(pods)
local podConfigMaps = {}
for _, pod in ipairs(pods) do
if pod.spec.containers ~= nil then
for _, container in ipairs(pod.spec.containers) do
if container.env ~= nil then
for _, env in ipairs(container.env) do
if env.valueFrom ~= nil and env.valueFrom.configMapKeyRef ~= nil then
key = getKey(pod.metadata.namespace, env.valueFrom.configMapKeyRef.name)
podConfigMaps[key] = true
end
end
end
if container.envFrom ~= nil then
for _, envFrom in ipairs(container.envFrom) do
if envFrom.configMapRef ~= nil then
key = getKey(pod.metadata.namespace, envFrom.configMapRef.name)
podConfigMaps[key] = true
end
end
end
end
end
if pod.spec.initContainers ~= nil then
for _, initContainer in ipairs(pod.spec.initContainers) do
if initContainer.env ~= nil then
for _, env in ipairs(initContainer.env) do
if env.valueFrom ~= nil and env.valueFrom.configMapKeyRef ~= nil then
key = getKey(pod.metadata.namespace, env.valueFrom.configMapKeyRef.name)
podConfigMaps[key] = true
end
end
end
if initContainer.envFrom ~= nil then
for _, envFrom in ipairs(initContainer.envFrom) do
if envFrom.configMapRef ~= nil then
key = getKey(pod.metadata.namespace,envFrom.configMapRef.name)
podConfigMaps[key] = true
end
end
end
end
end
if pod.spec.volumes ~= nil then
for _, volume in ipairs(pod.spec.volumes) do
if volume.configMap ~= nil then
key = getKey(pod.metadata.namespace,volume.configMap.name)
podConfigMaps[key] = true
end
if volume.projected ~= nil and volume.projected.sources ~= nil then
for _, projectedResource in ipairs(volume.projected.sources) do
if projectedResource.configMap ~= nil then
key = getKey(pod.metadata.namespace,projectedResource.configMap.name)
podConfigMaps[key] = true
end
end
end
end
end
end
return podConfigMaps
end
function evaluate()
local hs = {}
hs.message = ""
local pods = {}
local configMaps = {}
local unusedConfigMaps = {}
-- Separate configMaps and podsfrom the resources
for _, resource in ipairs(resources) do
local kind = resource.kind
if kind == "ConfigMap" and not skipNamespace(resource.metadata.namespace) then
table.insert(configMaps, resource)
elseif kind == "Pod" then
table.insert(pods, resource)
end
end
podConfigMaps = configMapsUsedByPods(pods)
for _, configMap in ipairs(configMaps) do
key = getKey(configMap.metadata.namespace,configMap.metadata.name)
if not podConfigMaps[key] then
table.insert(unusedConfigMaps, {resource = configMap})
end
end
if #unusedConfigMaps > 0 then
hs.resources = unusedConfigMaps
end
return hs
end