205 lines
7.7 KiB
Python
Executable File
205 lines
7.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import logging
|
|
from string import Template
|
|
|
|
from ops.charm import CharmBase
|
|
from ops.main import main
|
|
from ops.model import ActiveStatus, MaintenanceStatus, WaitingStatus
|
|
|
|
from oci_image import OCIImageResource, OCIImageResourceError
|
|
|
|
|
|
class CoreDNSCharm(CharmBase):
|
|
def __init__(self, *args):
|
|
super().__init__(*args)
|
|
if not self.unit.is_leader():
|
|
# We can't do anything useful when not the leader, so do nothing.
|
|
self.model.unit.status = WaitingStatus('Waiting for leadership')
|
|
return
|
|
self.log = logging.getLogger(__name__)
|
|
self.image = OCIImageResource(self, 'coredns-image')
|
|
for event in [self.on.install,
|
|
self.on.leader_elected,
|
|
self.on.upgrade_charm,
|
|
self.on.config_changed]:
|
|
self.framework.observe(event, self.main)
|
|
self.framework.observe(self.on.dns_provider_relation_joined, self.provide_dns)
|
|
|
|
def main(self, event):
|
|
try:
|
|
image_details = self.image.fetch()
|
|
except OCIImageResourceError as e:
|
|
self.model.unit.status = e.status
|
|
return
|
|
|
|
self.model.unit.status = MaintenanceStatus('Setting pod spec')
|
|
|
|
corefile = Template(self.model.config['corefile'])
|
|
corefile = corefile.safe_substitute(self.model.config)
|
|
|
|
# Adapted from coredns.yaml.sed in https://github.com/coredns/ at 75a1cad
|
|
self.model.pod.set_spec({
|
|
'version': 3,
|
|
'service': {
|
|
'updateStrategy': {
|
|
'type': 'RollingUpdate',
|
|
'rollingUpdate': {'maxUnavailable': 1},
|
|
},
|
|
'annotations': {
|
|
'prometheus.io/port': "9153",
|
|
'prometheus.io/scrape': "true",
|
|
},
|
|
},
|
|
# Dropped by a regression; see:
|
|
# https://bugs.launchpad.net/juju/+bug/1895886
|
|
# 'priorityClassName': 'system-cluster-critical',
|
|
'containers': [{
|
|
'name': 'coredns',
|
|
'imageDetails': image_details,
|
|
'imagePullPolicy': 'IfNotPresent',
|
|
'args': ['-conf', '/etc/coredns/Corefile'],
|
|
'volumeConfig': [{
|
|
'name': 'config-volume',
|
|
'mountPath': '/etc/coredns',
|
|
# Not supported
|
|
# 'readOnly': True,
|
|
'files': [{
|
|
'path': 'Corefile',
|
|
'mode': 0o444,
|
|
'content': corefile,
|
|
}],
|
|
}],
|
|
'ports': [
|
|
{
|
|
'name': 'dns',
|
|
'containerPort': 53,
|
|
'protocol': 'UDP',
|
|
},
|
|
{
|
|
'name': 'dns-tcp',
|
|
'containerPort': 53,
|
|
'protocol': 'TCP',
|
|
},
|
|
{
|
|
'name': 'metrics',
|
|
'containerPort': 9153,
|
|
'protocol': 'TCP',
|
|
},
|
|
],
|
|
# Can't be specified by the charm yet; see:
|
|
# https://bugs.launchpad.net/juju/+bug/1893123
|
|
# 'resources': {
|
|
# 'limits': {'memory': '170Mi'},
|
|
# 'requests': {'cpu': '100m', 'memory': '70Mi'},
|
|
# },
|
|
'kubernetes': {
|
|
'securityContext': {
|
|
'allowPrivilegeEscalation': False,
|
|
'capabilities': {
|
|
'add': ['NET_BIND_SERVICE'],
|
|
'drop': ['all'],
|
|
},
|
|
'readOnlyRootFilesystem': True,
|
|
},
|
|
'livenessProbe': {
|
|
'httpGet': {
|
|
'path': '/health',
|
|
'port': 8080,
|
|
'scheme': 'HTTP',
|
|
},
|
|
'initialDelaySeconds': 60,
|
|
'timeoutSeconds': 5,
|
|
'successThreshold': 1,
|
|
'failureThreshold': 5,
|
|
},
|
|
'readinessProbe': {
|
|
'httpGet': {
|
|
'path': '/ready',
|
|
'port': 8181,
|
|
'scheme': 'HTTP',
|
|
},
|
|
},
|
|
},
|
|
}],
|
|
'serviceAccount': {
|
|
'roles': [{
|
|
'global': True,
|
|
'rules': [
|
|
{
|
|
'apigroups': ['discovery.k8s.io'],
|
|
'resources': [
|
|
'endpointslices',
|
|
],
|
|
'verbs': ['list', 'watch'],
|
|
},
|
|
{
|
|
'apigroups': [''],
|
|
'resources': [
|
|
'endpoints',
|
|
'services',
|
|
'pods',
|
|
'namespaces',
|
|
],
|
|
'verbs': ['list', 'watch'],
|
|
},
|
|
{
|
|
'apigroups': [''],
|
|
'resources': ['nodes'],
|
|
'verbs': ['get'],
|
|
},
|
|
],
|
|
}],
|
|
},
|
|
'kubernetesResources': {
|
|
'pod': {
|
|
'dnsPolicy': 'Default',
|
|
# Not yet supported by Juju; see:
|
|
# https://bugs.launchpad.net/juju/+bug/1895887
|
|
# 'tolerations': [{
|
|
# 'key': 'CriticalAddonsOnly',
|
|
# 'operator': 'Exists',
|
|
# }],
|
|
# 'affinity': {
|
|
# 'podAntiAffinity': {
|
|
# 'preferredDuringScheduling' +
|
|
# 'IgnoredDuringExecution': [{
|
|
# 'weight': 100,
|
|
# 'podAffinityTerm': {
|
|
# 'labelSelector': {
|
|
# 'matchExpressions': [{
|
|
# 'key': 'k8s-app',
|
|
# 'operator': 'In',
|
|
# 'values': ["kube-dns"],
|
|
# }],
|
|
# },
|
|
# 'topologyKey': 'kubernetes.io/hostname',
|
|
# },
|
|
# }],
|
|
# },
|
|
# },
|
|
# Can be done by the operator via placement (--to), but can't
|
|
# be specified by the charm yet, per same bug as above.
|
|
# 'nodeSelector': {
|
|
# 'kubernetes.io/os': 'linux',
|
|
# },
|
|
}
|
|
}
|
|
})
|
|
self.model.unit.status = ActiveStatus()
|
|
|
|
def provide_dns(self, event):
|
|
provided_data = event.relation.data[self.unit]
|
|
if not provided_data.get('ingress-address'):
|
|
event.defer()
|
|
return
|
|
provided_data.update({
|
|
'domain': self.model.config['domain'],
|
|
'sdn-ip': str(provided_data['ingress-address']),
|
|
'port': "53",
|
|
})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(CoreDNSCharm)
|