local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';

{
  _config+:: {
    namespace: 'default',

    versions+:: {
      prometheusAdapter: 'v0.7.0',
    },

    imageRepos+:: {
      prometheusAdapter: 'quay.io/coreos/k8s-prometheus-adapter-amd64',
    },

    prometheusAdapter+:: {
      name: 'prometheus-adapter',
      labels: { name: $._config.prometheusAdapter.name },
      prometheusURL: 'http://prometheus-' + $._config.prometheus.name + '.' + $._config.namespace + '.svc:9090/',
      config: {
        resourceRules: {
          cpu: {
            containerQuery: 'sum(irate(container_cpu_usage_seconds_total{<<.LabelMatchers>>,container!="POD",container!="",pod!=""}[5m])) by (<<.GroupBy>>)',
            nodeQuery: 'sum(1 - irate(node_cpu_seconds_total{mode="idle"}[5m]) * on(namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:{<<.LabelMatchers>>}) by (<<.GroupBy>>)',
            resources: {
              overrides: {
                node: {
                  resource: 'node'
                },
                namespace: {
                  resource: 'namespace'
                },
                pod: {
                  resource: 'pod'
                },
              },
            },
            containerLabel: 'container'
          },
          memory: {
            containerQuery: 'sum(container_memory_working_set_bytes{<<.LabelMatchers>>,container!="POD",container!="",pod!=""}) by (<<.GroupBy>>)',
            nodeQuery: 'sum(node_memory_MemTotal_bytes{job="node-exporter",<<.LabelMatchers>>} - node_memory_MemAvailable_bytes{job="node-exporter",<<.LabelMatchers>>}) by (<<.GroupBy>>)',
            resources: {
              overrides: {
                instance: {
                  resource: 'node'
                },
                namespace: {
                  resource: 'namespace'
                },
                pod: {
                  resource: 'pod'
                },
              },
            },
            containerLabel: 'container'
          },
          window: '5m',
        },
      }
    },
  },

  prometheusAdapter+:: {
    apiService:
      {
        apiVersion: 'apiregistration.k8s.io/v1',
        kind: 'APIService',
        metadata: {
          name: 'v1beta1.metrics.k8s.io',
        },
        spec: {
          service: {
            name: $.prometheusAdapter.service.metadata.name,
            namespace: $._config.namespace,
          },
          group: 'metrics.k8s.io',
          version: 'v1beta1',
          insecureSkipTLSVerify: true,
          groupPriorityMinimum: 100,
          versionPriority: 100,
        },
      },

    configMap:
      local configmap = k.core.v1.configMap;
      configmap.new('adapter-config', { 'config.yaml': std.manifestYamlDoc($._config.prometheusAdapter.config) }) +

      configmap.mixin.metadata.withNamespace($._config.namespace),

    service:
      local service = k.core.v1.service;
      local servicePort = k.core.v1.service.mixin.spec.portsType;

      service.new(
        $._config.prometheusAdapter.name,
        $._config.prometheusAdapter.labels,
        servicePort.newNamed('https', 443, 6443),
      ) +
      service.mixin.metadata.withNamespace($._config.namespace) +
      service.mixin.metadata.withLabels($._config.prometheusAdapter.labels),

    deployment:
      local deployment = k.apps.v1.deployment;
      local volume = deployment.mixin.spec.template.spec.volumesType;
      local container = deployment.mixin.spec.template.spec.containersType;
      local containerVolumeMount = container.volumeMountsType;

      local c =
        container.new($._config.prometheusAdapter.name, $._config.imageRepos.prometheusAdapter + ':' + $._config.versions.prometheusAdapter) +
        container.withArgs([
          '--cert-dir=/var/run/serving-cert',
          '--config=/etc/adapter/config.yaml',
          '--logtostderr=true',
          '--metrics-relist-interval=1m',
          '--prometheus-url=' + $._config.prometheusAdapter.prometheusURL,
          '--secure-port=6443',
        ]) +
        container.withPorts([{ containerPort: 6443 }]) +
        container.withVolumeMounts([
          containerVolumeMount.new('tmpfs', '/tmp'),
          containerVolumeMount.new('volume-serving-cert', '/var/run/serving-cert'),
          containerVolumeMount.new('config', '/etc/adapter'),
        ],);

      deployment.new($._config.prometheusAdapter.name, 1, c, $._config.prometheusAdapter.labels) +
      deployment.mixin.metadata.withNamespace($._config.namespace) +
      deployment.mixin.spec.selector.withMatchLabels($._config.prometheusAdapter.labels) +
      deployment.mixin.spec.template.spec.withServiceAccountName($.prometheusAdapter.serviceAccount.metadata.name) +
      deployment.mixin.spec.template.spec.withNodeSelector({ 'kubernetes.io/os': 'linux' }) +
      deployment.mixin.spec.strategy.rollingUpdate.withMaxSurge(1) +
      deployment.mixin.spec.strategy.rollingUpdate.withMaxUnavailable(0) +
      deployment.mixin.spec.template.spec.withVolumes([
        volume.fromEmptyDir(name='tmpfs'),
        volume.fromEmptyDir(name='volume-serving-cert'),
        { name: 'config', configMap: { name: 'adapter-config' } },
      ]),

    serviceAccount:
      local serviceAccount = k.core.v1.serviceAccount;

      serviceAccount.new($._config.prometheusAdapter.name) +
      serviceAccount.mixin.metadata.withNamespace($._config.namespace),

    clusterRole:
      local clusterRole = k.rbac.v1.clusterRole;
      local policyRule = clusterRole.rulesType;

      local rules =
        policyRule.new() +
        policyRule.withApiGroups(['']) +
        policyRule.withResources(['nodes', 'namespaces', 'pods', 'services']) +
        policyRule.withVerbs(['get', 'list', 'watch']);

      clusterRole.new() +
      clusterRole.mixin.metadata.withName($._config.prometheusAdapter.name) +
      clusterRole.withRules(rules),

    clusterRoleBinding:
      local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;

      clusterRoleBinding.new() +
      clusterRoleBinding.mixin.metadata.withName($._config.prometheusAdapter.name) +
      clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') +
      clusterRoleBinding.mixin.roleRef.withName($.prometheusAdapter.clusterRole.metadata.name) +
      clusterRoleBinding.mixin.roleRef.mixinInstance({ kind: 'ClusterRole' }) +
      clusterRoleBinding.withSubjects([{
        kind: 'ServiceAccount',
        name: $.prometheusAdapter.serviceAccount.metadata.name,
        namespace: $._config.namespace,
      }]),

    clusterRoleBindingDelegator:
      local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;

      clusterRoleBinding.new() +
      clusterRoleBinding.mixin.metadata.withName('resource-metrics:system:auth-delegator') +
      clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') +
      clusterRoleBinding.mixin.roleRef.withName('system:auth-delegator') +
      clusterRoleBinding.mixin.roleRef.mixinInstance({ kind: 'ClusterRole' }) +
      clusterRoleBinding.withSubjects([{
        kind: 'ServiceAccount',
        name: $.prometheusAdapter.serviceAccount.metadata.name,
        namespace: $._config.namespace,
      }]),

    clusterRoleServerResources:
      local clusterRole = k.rbac.v1.clusterRole;
      local policyRule = clusterRole.rulesType;

      local rules =
        policyRule.new() +
        policyRule.withApiGroups(['metrics.k8s.io']) +
        policyRule.withResources(['*']) +
        policyRule.withVerbs(['*']);

      clusterRole.new() +
      clusterRole.mixin.metadata.withName('resource-metrics-server-resources') +
      clusterRole.withRules(rules),

    clusterRoleAggregatedMetricsReader:
      local clusterRole = k.rbac.v1.clusterRole;
      local policyRule = clusterRole.rulesType;

      local rules =
        policyRule.new() +
        policyRule.withApiGroups(['metrics.k8s.io']) +
        policyRule.withResources(['pods', 'nodes']) +
        policyRule.withVerbs(['get','list','watch']);

      clusterRole.new() +
      clusterRole.mixin.metadata.withName('system:aggregated-metrics-reader') +
      clusterRole.mixin.metadata.withLabels({
        "rbac.authorization.k8s.io/aggregate-to-admin": "true",
        "rbac.authorization.k8s.io/aggregate-to-edit": "true",
        "rbac.authorization.k8s.io/aggregate-to-view": "true",
      }) +
      clusterRole.withRules(rules),

    roleBindingAuthReader:
      local roleBinding = k.rbac.v1.roleBinding;

      roleBinding.new() +
      roleBinding.mixin.metadata.withName('resource-metrics-auth-reader') +
      roleBinding.mixin.metadata.withNamespace('kube-system') +
      roleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') +
      roleBinding.mixin.roleRef.withName('extension-apiserver-authentication-reader') +
      roleBinding.mixin.roleRef.mixinInstance({ kind: 'Role' }) +
      roleBinding.withSubjects([{
        kind: 'ServiceAccount',
        name: $.prometheusAdapter.serviceAccount.metadata.name,
        namespace: $._config.namespace,
      }]),
  },
}
