From 3129aae171da22d355275daaf79225fa6f2e238d Mon Sep 17 00:00:00 2001 From: Joe Elliott Date: Wed, 24 Feb 2021 16:13:35 -0500 Subject: [PATCH] Used statefulset anti affinity thing (#555) Signed-off-by: Joe Elliott --- example/tk/jsonnetfile.lock.json | 4 +- .../ksonnet-util/grafana.libsonnet | 71 +++ .../ksonnet-util/jaeger.libsonnet | 19 - .../ksonnet-util/k-compat.libsonnet | 22 + .../ksonnet-util/kausal.libsonnet | 450 +----------------- .../ksonnet-util/legacy-custom.libsonnet | 156 ++++++ .../ksonnet-util/legacy-noname.libsonnet | 51 ++ .../ksonnet-util/legacy-subtypes.libsonnet | 168 +++++++ .../ksonnet-util/legacy-types.libsonnet | 26 + .../jsonnet-libs/ksonnet-util/util.libsonnet | 249 ++++++++++ .../jsonnet/microservices/ingester.libsonnet | 2 +- .../jsonnet/microservices/memcached.libsonnet | 2 +- 12 files changed, 767 insertions(+), 453 deletions(-) create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/grafana.libsonnet delete mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/jaeger.libsonnet create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/k-compat.libsonnet mode change 100755 => 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-custom.libsonnet create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-noname.libsonnet create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-subtypes.libsonnet create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-types.libsonnet create mode 100644 example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/util.libsonnet diff --git a/example/tk/jsonnetfile.lock.json b/example/tk/jsonnetfile.lock.json index bdc6e651953..f73f2097a18 100644 --- a/example/tk/jsonnetfile.lock.json +++ b/example/tk/jsonnetfile.lock.json @@ -8,8 +8,8 @@ "subdir": "ksonnet-util" } }, - "version": "c19a92e586a6752f11745b47f309b13f02ef7147", - "sum": "LKsTTBcH8TXX5ANgRUu5I7Y1tf5le4nANFV3/W53I+c=" + "version": "eae352a28812274df34ccee8a7edec3a97a1ef95", + "sum": "sI6Hgng7yR8fkgHqJ10e3rQagVhpHhumAKqqzbOZUSM=" }, { "source": { diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/grafana.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/grafana.libsonnet new file mode 100644 index 00000000000..8277402227e --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/grafana.libsonnet @@ -0,0 +1,71 @@ +// grafana.libsonnet provides the k-compat layer with grafana-opinionated defaults +(import 'k-compat.libsonnet') ++ { + core+: { + v1+: { + containerPort+:: { + // Force all ports to have names. + new(name, port):: + super.newNamed(name=name, containerPort=port), + + // Shortcut constructor for UDP ports. + newUDP(name, port):: + super.newNamedUDP(name=name, containerPort=port), + }, + + container+:: { + new(name, image):: + super.new(name, image) + + super.withImagePullPolicy('IfNotPresent'), + }, + }, + }, + + local appsExtentions = { + daemonSet+: { + new(name, containers, podLabels={}):: + super.new(name, containers, podLabels={}) + + + // Can't think of a reason we wouldn't want a DaemonSet to run on + // every node. + super.mixin.spec.template.spec.withTolerations([ + $.core.v1.toleration.new() + + $.core.v1.toleration.withOperator('Exists') + + $.core.v1.toleration.withEffect('NoSchedule'), + ]) + + + // We want to specify a minReadySeconds on every deamonset, so we get some + // very basic canarying, for instance, with bad arguments. + super.mixin.spec.withMinReadySeconds(10) + + super.mixin.spec.updateStrategy.withType('RollingUpdate'), + }, + + deployment+: { + new(name, replicas, containers, podLabels={}):: + super.new(name, replicas, containers, podLabels) + + + // We want to specify a minReadySeconds on every deployment, so we get some + // very basic canarying, for instance, with bad arguments. + super.mixin.spec.withMinReadySeconds(10) + + + // We want to add a sensible default for the number of old deployments + // handing around. + super.mixin.spec.withRevisionHistoryLimit(10), + }, + + statefulSet+: { + new(name, replicas, containers, volumeClaims=[], podLabels={}):: + super.new(name, replicas, containers, volumeClaims, podLabels) + + super.mixin.spec.updateStrategy.withType('RollingUpdate'), + }, + }, + + extensions+: { + v1beta1+: appsExtentions, + }, + + apps+: { + v1beta1+: appsExtentions, + v1+: appsExtentions, + }, +} diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/jaeger.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/jaeger.libsonnet deleted file mode 100644 index 26702dec805..00000000000 --- a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/jaeger.libsonnet +++ /dev/null @@ -1,19 +0,0 @@ -{ - _config+:: { - cluster: error 'Must define a cluster', - namespace: error 'Must define a namespace', - jaeger_agent_host: null, - }, - - local container = $.core.v1.container, - - jaeger_mixin:: - if $._config.jaeger_agent_host == null - then {} - else - container.withEnvMixin([ - container.envType.new('JAEGER_AGENT_HOST', $._config.jaeger_agent_host), - container.envType.new('JAEGER_TAGS', 'namespace=%s,cluster=%s' % [$._config.namespace, $._config.cluster]), - container.envType.new('JAEGER_SAMPLER_MANAGER_HOST_PORT', 'http://%s:5778/sampling' % $._config.jaeger_agent_host), - ]), -} diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/k-compat.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/k-compat.libsonnet new file mode 100644 index 00000000000..65b5b6e26ba --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/k-compat.libsonnet @@ -0,0 +1,22 @@ +// k-compat.libsonnet provides a compatibility layer between k8s-alpha and ksonnet-lib. As ksonnet-lib has been +// abandoned, we consider it deprecated. This layer will generate a deprecation warning to those that still use it. +local k = import 'k.libsonnet'; + +k ++ ( + if std.objectHas(k, '__ksonnet') + then + std.trace( + 'Deprecated: ksonnet-lib has been abandoned, please consider using https://github.com/jsonnet-libs/k8s-alpha.', + (import 'legacy-types.libsonnet') + + (import 'legacy-custom.libsonnet') + + (import 'legacy-noname.libsonnet')({ + new(name=''):: super.new() + (if name != '' then super.mixin.metadata.withName(name) else {}), + }) + ) + else + (import 'legacy-subtypes.libsonnet') + + (import 'legacy-noname.libsonnet')({ + new(name=''):: super.new(name), + }) +) diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet old mode 100755 new mode 100644 index ec09e8aeef0..6a6f1498ee3 --- a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet @@ -1,439 +1,29 @@ -// Override defaults paramters for objects in the ksonnet libs here. -local k = import 'k.libsonnet'; +// kausal.libsonnet provides a backwards compatible way as many libraries leverage kausal.libsonnet. +// Ideally util.libsonnet is consumed separately. -k { +(import 'grafana.libsonnet') ++ { + local this = self, _config+:: { enable_rbac: true, enable_pod_priorities: false, namespace: error 'Must define a namespace', }, - core+: { - v1+: { - configMap+: { - new(name):: - super.new(name, {}), - withData(data):: - if (data == {}) then {} - else super.withData(data), - withDataMixin(data):: - if (data == {}) then {} - else super.withDataMixin(data), - }, - - // Expose containerPort type. - containerPort:: $.core.v1.container.portsType { - // Force all ports to have names. - new(name, port):: - super.newNamed(name=name, containerPort=port), - - // Shortcut constructor for UDP ports. - newUDP(name, port):: - super.newNamed(name=name, containerPort=port) + - super.withProtocol('UDP'), - }, - - // Expose volumes type. - volume:: $.core.v1.pod.mixin.spec.volumesType { - // Remove items parameter from fromConfigMap - fromConfigMap(name, configMapName):: - super.withName(name) + - super.mixin.configMap.withName(configMapName), - - // Shortcut constructor for secret volumes. - fromSecret(name, secret):: - super.withName(name) + - super.mixin.secret.withSecretName(secret), - }, - - volumeMount:: $.core.v1.container.volumeMountsType { - // Override new, such that it doesn't always set readOnly: false. - new(name, mountPath, readOnly=false):: - {} + self.withName(name) + self.withMountPath(mountPath) + - if readOnly - then self.withReadOnly(readOnly) - else {}, - }, - - persistentVolumeClaim+:: { - new():: {}, - }, - - container:: $.apps.v1.deployment.mixin.spec.template.spec.containersType { - new(name, image):: - super.new(name, image) + - super.withImagePullPolicy('IfNotPresent'), - - withEnvMixin(es):: - // if an envvar has an empty value ("") we want to remove that property - // because k8s will remove that and then it would always - // show up as a difference. - local removeEmptyValue(obj) = - if std.objectHas(obj, 'value') && std.length(obj.value) == 0 then - { - [k]: obj[k] - for k in std.objectFields(obj) - if k != 'value' - } - else - obj; - super.withEnvMixin([ - removeEmptyValue(envvar) - for envvar in es - ]), - - withEnvMap(es):: - self.withEnvMixin([ - $.core.v1.container.envType.new(k, es[k]) - for k in std.objectFields(es) - ]), - }, - - toleration:: $.apps.v1.deployment.mixin.spec.template.spec.tolerationsType, - - servicePort:: $.core.v1.service.mixin.spec.portsType, - }, - }, - - batch+: { - v1beta1+: { - cronJob+: { - new(name='', schedule='', containers=[]):: - super.new() + - ( - if name != '' then - super.mixin.metadata.withName(name) + - // set name label on pod - super.mixin.spec.jobTemplate.spec.template.metadata.withLabels({ name: name }) - else - {} - ) + - ( - if schedule != '' then - super.mixin.spec.withSchedule(schedule) - else - {} - ) + - super.mixin.spec.jobTemplate.spec.template.spec.withContainers(containers), - }, - }, - }, - - local appsExtentions = { - daemonSet+: { - new(name, containers):: - local labels = {name: name}; - - super.new() + - super.mixin.metadata.withName(name) + - super.mixin.spec.template.metadata.withLabels(labels) + - super.mixin.spec.template.spec.withContainers(containers) + - - // Can't think of a reason we wouldn't want a DaemonSet to run on - // every node. - super.mixin.spec.template.spec.withTolerations([ - $.core.v1.toleration.new() + - $.core.v1.toleration.withOperator('Exists') + - $.core.v1.toleration.withEffect('NoSchedule'), - ]) + - - // We want to specify a minReadySeconds on every deamonset, so we get some - // very basic canarying, for instance, with bad arguments. - super.mixin.spec.withMinReadySeconds(10) + - super.mixin.spec.updateStrategy.withType('RollingUpdate') + - - // apps.v1 requires an explicit selector: - super.mixin.spec.selector.withMatchLabels(labels), - }, - - deployment+: { - new(name, replicas, containers, podLabels={}):: - local labels = podLabels { name: name }; - - super.new(name, replicas, containers, labels) + - - // We want to specify a minReadySeconds on every deployment, so we get some - // very basic canarying, for instance, with bad arguments. - super.mixin.spec.withMinReadySeconds(10) + - - // We want to add a sensible default for the number of old deployments - // handing around. - super.mixin.spec.withRevisionHistoryLimit(10) + - - // apps.v1 requires an explicit selector: - super.mixin.spec.selector.withMatchLabels(labels), - }, - - statefulSet+: { - new(name, replicas, containers, volumeClaims, podLabels={}):: - local labels = podLabels { name: name }; - - super.new(name, replicas, containers, volumeClaims, labels) + - super.mixin.spec.updateStrategy.withType('RollingUpdate') + - - // apps.v1 requires an explicit selector: - super.mixin.spec.selector.withMatchLabels(labels) + - - // remove volumeClaimTemplates if empty (otherwise it will create a diff all the time) - (if std.length(volumeClaims) == 0 then { - spec+: { volumeClaimTemplates:: {} }, - } else {}), - }, - }, - - extensions+: { - v1beta1+: appsExtentions, - }, - - apps+: { - v1beta1+: appsExtentions, - v1+: appsExtentions, - }, - - rbac+: { - v1beta1+: { - // Shortcut to access the hidden types. - policyRule:: $.rbac.v1beta1.clusterRole.rulesType, - subject:: $.rbac.v1beta1.clusterRoleBinding.subjectsType, + util+:: + (import 'util.libsonnet').withK(this) + + { + rbac(name, rules):: + if $._config.enable_rbac + then super.rbac(name, rules, $._config.namespace) + else {}, + namespacedRBAC(name, rules):: + if $._config.enable_rbac + then super.namespacedRBAC(name, rules, $._config.namespace) + else {}, + podPriority(p): + if $._config.enable_pod_priorities + then super.podPriority(p) + else {}, }, - }, - - util+:: { - // mapToFlags converts a map to a set of golang-style command line flags. - mapToFlags(map, prefix='-'): [ - '%s%s=%s' % [prefix, key, map[key]] - for key in std.objectFields(map) - if map[key] != null - ], - - // serviceFor create service for a given deployment. - serviceFor(deployment, ignored_labels=[], nameFormat="%(container)s-%(port)s"):: - local container = $.core.v1.container; - local service = $.core.v1.service; - local servicePort = service.mixin.spec.portsType; - local ports = [ - servicePort.newNamed( - name=(nameFormat % {container: c.name, port: port.name}), - port=port.containerPort, - targetPort=port.containerPort - ) + - if std.objectHas(port, 'protocol') - then servicePort.withProtocol(port.protocol) - else {} - for c in deployment.spec.template.spec.containers - for port in (c + container.withPortsMixin([])).ports - ]; - local labels = { - [x]: deployment.spec.template.metadata.labels[x] - for x in std.objectFields(deployment.spec.template.metadata.labels) - if std.count(ignored_labels, x) == 0 - }; - - service.new( - deployment.metadata.name, // name - labels, // selector - ports, - ) + - service.mixin.metadata.withLabels({ name: deployment.metadata.name }), - - // rbac creates a service account, role and role binding with the given - // name and rules. - rbac(name, rules):: - if $._config.enable_rbac - then { - local clusterRole = $.rbac.v1beta1.clusterRole, - local clusterRoleBinding = $.rbac.v1beta1.clusterRoleBinding, - local subject = $.rbac.v1beta1.subject, - local serviceAccount = $.core.v1.serviceAccount, - - service_account: - serviceAccount.new(name), - - cluster_role: - clusterRole.new() + - clusterRole.mixin.metadata.withName(name) + - clusterRole.withRules(rules), - - cluster_role_binding: - clusterRoleBinding.new() + - clusterRoleBinding.mixin.metadata.withName(name) + - clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') + - clusterRoleBinding.mixin.roleRef.withKind('ClusterRole') + - clusterRoleBinding.mixin.roleRef.withName(name) + - clusterRoleBinding.withSubjects([ - subject.new() + - subject.withKind('ServiceAccount') + - subject.withName(name) + - subject.withNamespace($._config.namespace), - ]), - } - else {}, - - namespacedRBAC(name, rules):: - if $._config.enable_rbac - then { - local role = $.rbac.v1beta1.role, - local roleBinding = $.rbac.v1beta1.roleBinding, - local subject = $.rbac.v1beta1.subject, - local serviceAccount = $.core.v1.serviceAccount, - - service_account: - serviceAccount.new(name) + - serviceAccount.mixin.metadata.withNamespace($._config.namespace), - - role: - role.new() + - role.mixin.metadata.withName(name) + - role.mixin.metadata.withNamespace($._config.namespace) + - role.withRules(rules), - - cluster_role_binding: - roleBinding.new() + - roleBinding.mixin.metadata.withName(name) + - roleBinding.mixin.metadata.withNamespace($._config.namespace) + - roleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') + - roleBinding.mixin.roleRef.withKind('Role') + - roleBinding.mixin.roleRef.withName(name) + - roleBinding.withSubjects([ - subject.new() + - subject.withKind('ServiceAccount') + - subject.withName(name) + - subject.withNamespace($._config.namespace), - ]), - } - else {}, - - // VolumeMount helper functions can be augmented with mixins. - // For example, passing "volumeMount.withSubPath(subpath)" will result in - // a subpath mixin. - configVolumeMount(name, path, volumeMountMixin={}):: - local container = $.core.v1.container, - deployment = $.apps.v1.deployment, - volumeMount = $.core.v1.volumeMount, - volume = $.core.v1.volume, - addMount(c) = c + container.withVolumeMountsMixin( - volumeMount.new(name, path) + - volumeMountMixin, - ); - - deployment.mapContainers(addMount) + - deployment.mixin.spec.template.spec.withVolumesMixin([ - volume.fromConfigMap(name, name), - ]), - - // configMapVolumeMount adds a configMap to deployment-like objects. - // It will also add an annotation hash to ensure the pods are re-deployed - // when the config map changes. - configMapVolumeMount(configMap, path, volumeMountMixin={}):: - local name = configMap.metadata.name, - hash = std.md5(std.toString(configMap)), - container = $.core.v1.container, - deployment = $.apps.v1.deployment, - volumeMount = $.core.v1.volumeMount, - volume = $.core.v1.volume, - addMount(c) = c + container.withVolumeMountsMixin( - volumeMount.new(name, path) + - volumeMountMixin, - ); - - deployment.mapContainers(addMount) + - deployment.mixin.spec.template.spec.withVolumesMixin([ - volume.fromConfigMap(name, name), - ]) + - deployment.mixin.spec.template.metadata.withAnnotationsMixin({ - ['%s-hash' % name]: hash, - }), - - hostVolumeMount(name, hostPath, path, readOnly=false, volumeMountMixin={}):: - local container = $.core.v1.container, - deployment = $.apps.v1.deployment, - volumeMount = $.core.v1.volumeMount, - volume = $.core.v1.volume, - addMount(c) = c + container.withVolumeMountsMixin( - volumeMount.new(name, path, readOnly=readOnly) + - volumeMountMixin, - ); - - deployment.mapContainers(addMount) + - deployment.mixin.spec.template.spec.withVolumesMixin([ - volume.fromHostPath(name, hostPath), - ]), - - secretVolumeMount(name, path, defaultMode=256, volumeMountMixin={}):: - local container = $.core.v1.container, - deployment = $.apps.v1.deployment, - volumeMount = $.core.v1.volumeMount, - volume = $.core.v1.volume, - addMount(c) = c + container.withVolumeMountsMixin( - volumeMount.new(name, path) + - volumeMountMixin, - ); - - deployment.mapContainers(addMount) + - deployment.mixin.spec.template.spec.withVolumesMixin([ - volume.fromSecret(name, name) + - volume.mixin.secret.withDefaultMode(defaultMode), - ]), - - emptyVolumeMount(name, path, volumeMountMixin={}, volumeMixin={}):: - local container = $.core.v1.container, - deployment = $.apps.v1.deployment, - volumeMount = $.core.v1.volumeMount, - volume = $.core.v1.volume, - addMount(c) = c + container.withVolumeMountsMixin( - volumeMount.new(name, path) + - volumeMountMixin, - ); - - deployment.mapContainers(addMount) + - deployment.mixin.spec.template.spec.withVolumesMixin([ - volume.fromEmptyDir(name) + volumeMixin, - ]), - - manifestYaml(value):: ( - local f = std.native('manifestYamlFromJson'); - f(std.toString(value)) - ), - - resourcesRequests(cpu, memory):: - $.core.v1.container.mixin.resources.withRequests( - (if cpu != null - then { cpu: cpu } - else {}) + - (if memory != null - then { memory: memory } - else {}) - ), - - resourcesLimits(cpu, memory):: - $.core.v1.container.mixin.resources.withLimits( - (if cpu != null - then { cpu: cpu } - else {}) + - (if memory != null - then { memory: memory } - else {}) - ), - - antiAffinity: - { - local deployment = $.apps.v1.deployment, - local podAntiAffinity = deployment.mixin.spec.template.spec.affinity.podAntiAffinity, - local name = super.spec.template.metadata.labels.name, - - spec+: podAntiAffinity.withRequiredDuringSchedulingIgnoredDuringExecution([ - podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.new() + - podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.mixin.labelSelector.withMatchLabels({ name: name }) + - podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.withTopologyKey('kubernetes.io/hostname'), - ]).spec, - }, - - // Add a priority to the pods in a deployment (or deployment-like objects - // such as a statefulset) iff _config.enable_pod_priorities is set to true. - podPriority(p): - local deployment = $.apps.v1.deployment; - if $._config.enable_pod_priorities - then deployment.mixin.spec.template.spec.withPriorityClassName(p) - else {}, - }, } diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-custom.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-custom.libsonnet new file mode 100644 index 00000000000..e81e6a85f27 --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-custom.libsonnet @@ -0,0 +1,156 @@ +// legacy-custom.libsonnet retrofits k8s-alpha functionality into ksonnet-lib +{ + core+: { + v1+: { + configMap+: { + // allow configMap without data + new(name, data={}):: + super.new(name, data), + withData(data):: + // don't add 'data' key if data={} + if (data == {}) then {} + else super.withData(data), + withDataMixin(data):: + // don't add 'data' key if data={} + if (data == {}) then {} + else super.withDataMixin(data), + }, + + volume+:: { + // Make items parameter optional from fromConfigMap + fromConfigMap(name, configMapName, configMapItems=[]):: + { + configMap+: + if configMapItems == [] then { items:: null } + else {}, + } + + super.fromConfigMap(name, configMapName, configMapItems), + + // Shortcut constructor for secret volumes. + fromSecret(name, secretName):: + super.withName(name) + + super.mixin.secret.withSecretName(secretName), + + // Rename emptyDir to claimName + fromPersistentVolumeClaim(name='', claimName=''):: super.fromPersistentVolumeClaim(name=name, emptyDir=claimName), + }, + + volumeMount+:: { + // Override new, such that it doesn't always set readOnly: false. + new(name, mountPath, readOnly=false):: + {} + self.withName(name) + self.withMountPath(mountPath) + + if readOnly + then self.withReadOnly(readOnly) + else {}, + }, + + containerPort+:: { + // Shortcut constructor for UDP ports. + newNamedUDP(name, containerPort):: + super.newNamed(name=name, containerPort=containerPort) + + super.withProtocol('UDP'), + }, + + persistentVolumeClaim+:: { + new(name=''):: + super.new() + + (if name != '' + then super.mixin.metadata.withName(name) + else {}), + }, + + container+:: { + withEnvMixin(es):: + // if an envvar has an empty value ("") we want to remove that property + // because k8s will remove that and then it would always + // show up as a difference. + local removeEmptyValue(obj) = + if std.objectHas(obj, 'value') && std.length(obj.value) == 0 then + { + [k]: obj[k] + for k in std.objectFields(obj) + if k != 'value' + } + else + obj; + super.withEnvMixin([ + removeEmptyValue(envvar) + for envvar in es + ]), + + withEnvMap(es):: + self.withEnvMixin([ + $.core.v1.envVar.new(k, es[k]) + for k in std.objectFields(es) + ]), + }, + }, + }, + + batch+: { + v1beta1+: { + cronJob+: { + new(name='', schedule='', containers=[]):: + super.new() + + super.mixin.spec.jobTemplate.spec.template.spec.withContainers(containers) + + (if name != '' + then + super.mixin.metadata.withName(name) + + super.mixin.spec.jobTemplate.spec.template.metadata.withLabels({ name: name }) + else {}) + + ( + if schedule != '' + then super.mixin.spec.withSchedule(schedule) + else {} + ), + }, + }, + }, + + local appsExtentions = { + daemonSet+: { + new(name, containers, podLabels={}):: + local labels = podLabels { name: name }; + super.new() + + super.mixin.metadata.withName(name) + + super.mixin.spec.template.metadata.withLabels(labels) + + super.mixin.spec.template.spec.withContainers(containers) + + // apps.v1 requires an explicit selector: + super.mixin.spec.selector.withMatchLabels(labels), + }, + deployment+: { + new(name, replicas, containers, podLabels={}):: + local labels = podLabels { name: name }; + super.new(name, replicas, containers, labels) + + + // apps.v1 requires an explicit selector: + super.mixin.spec.selector.withMatchLabels(labels), + }, + statefulSet+: { + new(name, replicas, containers, volumeClaims=[], podLabels={}):: + local labels = podLabels { name: name }; + super.new(name, replicas, containers, volumeClaims, labels) + + + // apps.v1 requires an explicit selector: + super.mixin.spec.selector.withMatchLabels(labels) + + + // remove volumeClaimTemplates if empty + // (otherwise it will create a diff all the time) + ( + if std.length(volumeClaims) > 0 + then super.mixin.spec.withVolumeClaimTemplates(volumeClaims) + else {} + ), + }, + }, + + extensions+: { + v1beta1+: appsExtentions, + }, + + apps+: { + v1beta1+: appsExtentions, + v1+: appsExtentions, + }, + +} diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-noname.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-noname.libsonnet new file mode 100644 index 00000000000..388a10b98ed --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-noname.libsonnet @@ -0,0 +1,51 @@ +// legacy-noname.libsonnet provides two-way compatibility, in k8s-alpha many new() functions have a mandatory name +// argument while they are absent in ksonnet-lib. `noNewEmptyNameMixin` allows us to make the argument optional in +// either situation. +function(noNewEmptyNameMixin) { + core+: { v1+: { + persistentVolumeClaim+: noNewEmptyNameMixin, + } }, + extensions+: { + v1beta1+: { + ingress+: noNewEmptyNameMixin, + }, + }, + networking+: { + v1beta1+: { + ingress+: noNewEmptyNameMixin, + }, + }, + batch+: { + v1+: { + job+: noNewEmptyNameMixin, + }, + v1beta1+: { + job+: noNewEmptyNameMixin, + }, + }, + local rbacPatch = { + role+: noNewEmptyNameMixin, + clusterRole+: noNewEmptyNameMixin, + roleBinding+: noNewEmptyNameMixin, + clusterRoleBinding+: noNewEmptyNameMixin, + }, + rbac+: { + v1+: rbacPatch, + v1beta1+: rbacPatch, + }, + policy+: { v1beta1+: { + podDisruptionBudget+: noNewEmptyNameMixin, + podSecurityPolicy+: noNewEmptyNameMixin, + } }, + storage+: { v1+: { + storageClass+: noNewEmptyNameMixin, + } }, + + scheduling+: { v1beta1+: { + priorityClass+: noNewEmptyNameMixin, + } }, + admissionregistration+: { v1beta1+: { + mutatingWebhookConfiguration+: noNewEmptyNameMixin, + validatingWebhookConfiguration+: noNewEmptyNameMixin, + } }, +} diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-subtypes.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-subtypes.libsonnet new file mode 100644 index 00000000000..0beddfcd7a6 --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-subtypes.libsonnet @@ -0,0 +1,168 @@ +// legacy-subtypes.libsonnet makes first-class entities available as subtypes like in ksonnet-lib. +// It also makes the empty new() functions and camelCased functions available. +// This is largely based on kausal-shim.libsonnet from k8s-alpha. +{ + core+: { v1+: { + container+: { + envType: $.core.v1.envVar, + envFromType: $.core.v1.envFromSource, + portsType: $.core.v1.containerPort, + volumeMountsType: $.core.v1.volumeMount, + }, + pod+: { + spec+: { + volumesType: $.core.v1.volume, + }, + }, + service+: { + spec+: { + withClusterIp: self.withClusterIP, + withLoadBalancerIp: self.withLoadBalancerIP, + portsType: $.core.v1.servicePort, + }, + }, + + envFromSource+: { new():: {} }, + nodeSelector+: { new():: {} }, + nodeSelectorTerm+: { new():: {} }, + podAffinityTerm+: { new():: {} }, + preferredSchedulingTerm+: { new():: {} }, + toleration+: { new():: {} }, + localObjectReference+: { new():: {} }, + } }, + + local appsAffinityPatch = { + nodeAffinity+: { + requiredDuringSchedulingIgnoredDuringExecutionType: $.core.v1.nodeSelector { + nodeSelectorTermsType: $.core.v1.nodeSelectorTerm { + matchFieldsType: $.core.v1.nodeSelectorRequirement, + }, + }, + preferredDuringSchedulingIgnoredDuringExecutionType: $.core.v1.preferredSchedulingTerm { + preferenceType: { + matchFieldsType: $.core.v1.nodeSelectorRequirement, + }, + }, + }, + podAntiAffinity+: { + requiredDuringSchedulingIgnoredDuringExecutionType: $.core.v1.podAffinityTerm, + }, + }, + + local appsPatch = { + deployment+: { + spec+: { template+: { spec+: { + volumesType: $.core.v1.volume, + containersType: $.core.v1.container, + tolerationsType: $.core.v1.toleration, + affinity+: appsAffinityPatch, + } } }, + }, + daemonSet+: { + spec+: { template+: { spec+: { + withHostPid:: self.withHostPID, + tolerationsType: $.core.v1.toleration, + affinity+: appsAffinityPatch, + } } }, + }, + statefulSet+: { + spec+: { template+: { spec+: { + volumesType: $.core.v1.volume, + affinity+: appsAffinityPatch, + tolerationsType: $.core.v1.toleration, + imagePullSecretsType: $.core.v1.localObjectReference, + } } }, + }, + }, + + apps+: { + v1+: appsPatch, + v1beta1+: appsPatch, + }, + extensions+: { + v1beta1+: appsPatch { + ingress+: { + spec+: { + rulesType: $.extensions.v1beta1.ingressRule { + httpType+: { pathsType: $.extensions.v1beta1.httpIngressPath }, + }, + }, + }, + }, + }, + + batch+: { + local patch = { + mixin+: { spec+: { jobTemplate+: { spec+: { template+: { spec+: { + imagePullSecretsType: $.core.v1.localObjectReference, + } } } } } }, + }, + + v1+: { + job+: patch, + cronJob+: patch, + }, + v1beta1+: { + job+: patch, + cronJob+: patch, + }, + }, + + + local rbacPatch = { + local role = { + rulesType: $.rbac.v1beta1.policyRule, + }, + role+: role, + clusterRole+: role, + + local binding = { + subjectsType: $.rbac.v1beta1.subject, + }, + roleBinding+: binding, + clusterRoleBinding+: binding, + subject+: { new():: {} }, + + policyRule+: { + new():: {}, + withNonResourceUrls: self.withNonResourceURLs, + }, + }, + rbac+: { + v1+: rbacPatch, + v1beta1+: rbacPatch, + }, + + policy+: { + v1beta1+: { + idRange+: { new():: {} }, + podSecurityPolicy+: { + mixin+: { spec+: { + runAsUser+: { rangesType: $.policy.v1beta1.idRange }, + withHostIpc: self.withHostIPC, + withHostPid: self.withHostPID, + } }, + }, + }, + }, + + admissionregistration+: { v1beta1+: { + webhook+: { new():: {} }, + ruleWithOperations+: { new():: {} }, + local webhooksType = $.admissionregistration.v1beta1.webhook { + rulesType: $.admissionregistration.v1beta1.ruleWithOperations, + mixin+: { namespaceSelector+: { matchExpressionsType: { + new():: {}, + withKey(key):: { key: key }, + withOperator(operator):: { operator: operator }, + withValues(values):: { values: if std.isArray(values) then values else [values] }, + } } }, + }, + mutatingWebhookConfiguration+: { + webhooksType: webhooksType, + }, + validatingWebhookConfiguration+: { + webhooksType: webhooksType, + }, + } }, +} diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-types.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-types.libsonnet new file mode 100644 index 00000000000..b339021a935 --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/legacy-types.libsonnet @@ -0,0 +1,26 @@ +// legacy-types.libsonnet exposes hidden types from ksonnet-lib as first class citizens +// This list is likely to be incomplete. +{ + core+: { + v1+: { + container:: $.apps.v1.deployment.mixin.spec.template.spec.containersType, + containerPort:: $.core.v1.container.portsType, + envVar:: $.core.v1.container.envType, + envFromSource:: $.core.v1.container.envFromType, + servicePort:: $.core.v1.service.mixin.spec.portsType, + toleration:: $.apps.v1.deployment.mixin.spec.template.spec.tolerationsType, + volume:: $.core.v1.pod.mixin.spec.volumesType, + volumeMount:: $.core.v1.container.volumeMountsType, + }, + }, + rbac+: { + v1+: { + policyRule:: $.rbac.v1beta1.clusterRole.rulesType, + subject:: $.rbac.v1beta1.clusterRoleBinding.subjectsType, + }, + v1beta1+: { + policyRule:: $.rbac.v1beta1.clusterRole.rulesType, + subject:: $.rbac.v1beta1.clusterRoleBinding.subjectsType, + }, + }, +} diff --git a/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/util.libsonnet b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/util.libsonnet new file mode 100644 index 00000000000..c9458466ae1 --- /dev/null +++ b/example/tk/vendor/github.com/grafana/jsonnet-libs/ksonnet-util/util.libsonnet @@ -0,0 +1,249 @@ +// util.libsonnet provides a number of useful (opinionated) shortcuts to replace boilerplate code + +local util(k) = { + // mapToFlags converts a map to a set of golang-style command line flags. + mapToFlags(map, prefix='-'): [ + '%s%s=%s' % [prefix, key, map[key]] + for key in std.objectFields(map) + if map[key] != null + ], + + // serviceFor create service for a given deployment. + serviceFor(deployment, ignored_labels=[], nameFormat='%(container)s-%(port)s'):: + local container = k.core.v1.container; + local service = k.core.v1.service; + local servicePort = k.core.v1.servicePort; + local ports = [ + servicePort.newNamed( + name=(nameFormat % { container: c.name, port: port.name }), + port=port.containerPort, + targetPort=port.containerPort + ) + + if std.objectHas(port, 'protocol') + then servicePort.withProtocol(port.protocol) + else {} + for c in deployment.spec.template.spec.containers + for port in (c + container.withPortsMixin([])).ports + ]; + local labels = { + [x]: deployment.spec.template.metadata.labels[x] + for x in std.objectFields(deployment.spec.template.metadata.labels) + if std.count(ignored_labels, x) == 0 + }; + + service.new( + deployment.metadata.name, // name + labels, // selector + ports, + ) + + service.mixin.metadata.withLabels({ name: deployment.metadata.name }), + + // rbac creates a service account, role and role binding with the given + // name and rules. + rbac(name, rules, namespace):: { + local clusterRole = k.rbac.v1.clusterRole, + local clusterRoleBinding = k.rbac.v1.clusterRoleBinding, + local subject = k.rbac.v1.subject, + local serviceAccount = k.core.v1.serviceAccount, + + service_account: + serviceAccount.new(name), + + cluster_role: + clusterRole.new() + + clusterRole.mixin.metadata.withName(name) + + clusterRole.withRules(rules), + + cluster_role_binding: + clusterRoleBinding.new() + + clusterRoleBinding.mixin.metadata.withName(name) + + clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') + + clusterRoleBinding.mixin.roleRef.withKind('ClusterRole') + + clusterRoleBinding.mixin.roleRef.withName(name) + + clusterRoleBinding.withSubjects([ + subject.new() + + subject.withKind('ServiceAccount') + + subject.withName(name) + + subject.withNamespace(namespace), + ]), + }, + + namespacedRBAC(name, rules, namespace):: { + local role = k.rbac.v1.role, + local roleBinding = k.rbac.v1.roleBinding, + local subject = k.rbac.v1.subject, + local serviceAccount = k.core.v1.serviceAccount, + + service_account: + serviceAccount.new(name) + + serviceAccount.mixin.metadata.withNamespace(namespace), + + role: + role.new() + + role.mixin.metadata.withName(name) + + role.mixin.metadata.withNamespace(namespace) + + role.withRules(rules), + + cluster_role_binding: + roleBinding.new() + + roleBinding.mixin.metadata.withName(name) + + roleBinding.mixin.metadata.withNamespace(namespace) + + roleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') + + roleBinding.mixin.roleRef.withKind('Role') + + roleBinding.mixin.roleRef.withName(name) + + roleBinding.withSubjects([ + subject.new() + + subject.withKind('ServiceAccount') + + subject.withName(name) + + subject.withNamespace(namespace), + ]), + }, + + // VolumeMount helper functions can be augmented with mixins. + // For example, passing "volumeMount.withSubPath(subpath)" will result in + // a subpath mixin. + configVolumeMount(name, path, volumeMountMixin={}):: + local container = k.core.v1.container, + deployment = k.apps.v1.deployment, + volumeMount = k.core.v1.volumeMount, + volume = k.core.v1.volume, + addMount(c) = c + container.withVolumeMountsMixin( + volumeMount.new(name, path) + + volumeMountMixin, + ); + + deployment.mapContainers(addMount) + + deployment.mixin.spec.template.spec.withVolumesMixin([ + volume.fromConfigMap(name, name), + ]), + + // configMapVolumeMount adds a configMap to deployment-like objects. + // It will also add an annotation hash to ensure the pods are re-deployed + // when the config map changes. + configMapVolumeMount(configMap, path, volumeMountMixin={}):: + local name = configMap.metadata.name, + hash = std.md5(std.toString(configMap)), + container = k.core.v1.container, + deployment = k.apps.v1.deployment, + volumeMount = k.core.v1.volumeMount, + volume = k.core.v1.volume, + addMount(c) = c + container.withVolumeMountsMixin( + volumeMount.new(name, path) + + volumeMountMixin, + ); + + deployment.mapContainers(addMount) + + deployment.mixin.spec.template.spec.withVolumesMixin([ + volume.fromConfigMap(name, name), + ]) + + deployment.mixin.spec.template.metadata.withAnnotationsMixin({ + ['%s-hash' % name]: hash, + }), + + hostVolumeMount(name, hostPath, path, readOnly=false, volumeMountMixin={}):: + local container = k.core.v1.container, + deployment = k.apps.v1.deployment, + volumeMount = k.core.v1.volumeMount, + volume = k.core.v1.volume, + addMount(c) = c + container.withVolumeMountsMixin( + volumeMount.new(name, path, readOnly=readOnly) + + volumeMountMixin, + ); + + deployment.mapContainers(addMount) + + deployment.mixin.spec.template.spec.withVolumesMixin([ + volume.fromHostPath(name, hostPath), + ]), + + secretVolumeMount(name, path, defaultMode=256, volumeMountMixin={}):: + local container = k.core.v1.container, + deployment = k.apps.v1.deployment, + volumeMount = k.core.v1.volumeMount, + volume = k.core.v1.volume, + addMount(c) = c + container.withVolumeMountsMixin( + volumeMount.new(name, path) + + volumeMountMixin, + ); + + deployment.mapContainers(addMount) + + deployment.mixin.spec.template.spec.withVolumesMixin([ + volume.fromSecret(name, secretName=name) + + volume.mixin.secret.withDefaultMode(defaultMode), + ]), + + emptyVolumeMount(name, path, volumeMountMixin={}, volumeMixin={}):: + local container = k.core.v1.container, + deployment = k.apps.v1.deployment, + volumeMount = k.core.v1.volumeMount, + volume = k.core.v1.volume, + addMount(c) = c + container.withVolumeMountsMixin( + volumeMount.new(name, path) + + volumeMountMixin, + ); + + deployment.mapContainers(addMount) + + deployment.mixin.spec.template.spec.withVolumesMixin([ + volume.fromEmptyDir(name) + volumeMixin, + ]), + + manifestYaml(value):: ( + local f = std.native('manifestYamlFromJson'); + f(std.toString(value)) + ), + + resourcesRequests(cpu, memory):: + k.core.v1.container.mixin.resources.withRequests( + (if cpu != null + then { cpu: cpu } + else {}) + + (if memory != null + then { memory: memory } + else {}) + ), + + resourcesLimits(cpu, memory):: + k.core.v1.container.mixin.resources.withLimits( + (if cpu != null + then { cpu: cpu } + else {}) + + (if memory != null + then { memory: memory } + else {}) + ), + + antiAffinity: + { + local deployment = k.apps.v1.deployment, + local podAntiAffinity = deployment.mixin.spec.template.spec.affinity.podAntiAffinity, + local name = super.spec.template.metadata.labels.name, + + spec+: podAntiAffinity.withRequiredDuringSchedulingIgnoredDuringExecution([ + podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.new() + + podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.mixin.labelSelector.withMatchLabels({ name: name }) + + podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.withTopologyKey('kubernetes.io/hostname'), + ]).spec, + }, + + antiAffinityStatefulSet: + { + local statefulSet = k.apps.v1.statefulSet, + local podAntiAffinity = statefulSet.mixin.spec.template.spec.affinity.podAntiAffinity, + local name = super.spec.template.metadata.labels.name, + + spec+: podAntiAffinity.withRequiredDuringSchedulingIgnoredDuringExecution([ + podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.new() + + podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.mixin.labelSelector.withMatchLabels({ name: name }) + + podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecutionType.withTopologyKey('kubernetes.io/hostname'), + ]).spec, + }, + + // Add a priority to the pods in a deployment (or deployment-like objects + // such as a statefulset). + local deployment = k.apps.v1.deployment, + podPriority(p): + deployment.mixin.spec.template.spec.withPriorityClassName(p), +}; + +util((import 'grafana.libsonnet')) + { + withK(k):: util(k), +} diff --git a/operations/jsonnet/microservices/ingester.libsonnet b/operations/jsonnet/microservices/ingester.libsonnet index 8e535faa42f..5b179154fed 100644 --- a/operations/jsonnet/microservices/ingester.libsonnet +++ b/operations/jsonnet/microservices/ingester.libsonnet @@ -48,7 +48,7 @@ [$._config.gossip_member_label]: 'true', }, ) - + $.util.antiAffinity + + $.util.antiAffinityStatefulSet + statefulset.mixin.spec.withServiceName(target_name) + statefulset.mixin.spec.template.spec.withVolumes([ volume.fromConfigMap(tempo_config_volume, $.tempo_configmap.metadata.name), diff --git a/operations/jsonnet/microservices/memcached.libsonnet b/operations/jsonnet/microservices/memcached.libsonnet index b6db4790c8e..fe0c9454ab5 100644 --- a/operations/jsonnet/microservices/memcached.libsonnet +++ b/operations/jsonnet/microservices/memcached.libsonnet @@ -14,7 +14,7 @@ memcached { self.memcached_exporter, ], []) + statefulSet.mixin.spec.withServiceName(self.name) + - $.util.antiAffinity, + $.util.antiAffinityStatefulSet, local service = $.core.v1.service,