import * as pulumi from '@pulumi/pulumi'; import * as kubernetes from '@pulumi/kubernetes'; import * as random from '@pulumi/random'; import * as abstractions from '@kloudlib/abstractions'; import * as path from 'path'; import { merge } from 'lodash'; export interface KubernetesGrafanaInputs { provider?: kubernetes.Provider; namespace?: pulumi.Input; /** * import dasboards into grafana. * defaults to undefined. */ dashboards?: Array; /** * grafana datasources */ datasources?: GrafanaDataSource[]; /** * grafana plugins */ plugins?: string[]; /** * allowAnonymousAccess configures grafana so that * users can access it without needing to login. * defaults to false */ allowAnonymousAccess?: boolean; /** * */ grafanaConfig?: pulumi.Input>>; /** * ingress resource configuration * defaults to undefined (no ingress resource will be created) */ ingress?: abstractions.Ingress; /** * persistent storage configuration * defaults to undefined (no persistent storage will be used) */ persistence?: abstractions.Persistence; } export type GrafanaDashboard = { name: string } & ( | { json: string } | { file: string } | { gnetId: number; revision?: number; datasource?: string } | { url: string; b64content?: boolean } ); export interface GrafanaDataSource { name: string; type: 'prometheus' | 'loki'; url: pulumi.Input; } export interface KubernetesGrafanaOutputs { adminUsername: pulumi.Output; adminPassword: pulumi.Output; ingress: pulumi.Output; persistence: pulumi.Output; } /** * @noInheritDoc */ export class KubernetesGrafana extends pulumi.ComponentResource implements KubernetesGrafanaOutputs { readonly adminUsername: pulumi.Output; readonly adminPassword: pulumi.Output; readonly ingress: pulumi.Output; readonly persistence: pulumi.Output; constructor(name: string, props?: KubernetesGrafanaInputs, opts?: pulumi.CustomResourceOptions) { super('cloud:kubernetes:KubernetesGrafana', name, props, opts); this.ingress = pulumi.output(props?.ingress); this.persistence = pulumi.output(props?.persistence); const password = new random.RandomPassword( `${name}-admin-password`, { length: 32, special: false, }, { parent: this, } ); this.adminUsername = pulumi.output('admin'); this.adminPassword = pulumi.secret(password.result); const config = pulumi.output(props?.ingress?.hosts).apply((hosts) => ({ server: hosts && { domain: hosts[0], root_url: `https://${hosts[0]}`, }, 'auth.anonymous': { enabled: props?.allowAnonymousAccess ? 'true' : 'false', org_name: 'Main Org.', org_role: 'Editor', }, 'auth.basic': { enabled: 'false', }, })); const grafanaIni = pulumi .all([config, props?.grafanaConfig || {}]) .apply(([base, extra]) => merge({}, base, extra)); new kubernetes.helm.v3.Chart( name, { namespace: props?.namespace, path: path.join(__dirname, 'charts/grafana'), values: { adminUser: this.adminUsername, adminPassword: this.adminPassword, ingress: !props?.ingress ? { enabled: false } : { enabled: props?.ingress.enabled ?? true, annotations: { 'kubernetes.io/ingress.class': props?.ingress.class ?? 'nginx', 'kubernetes.io/tls-acme': props?.ingress.tls === false ? 'false' : 'true', // "tls" defaults to true, so we'll activate tls for undefined or null values ...props?.ingress.annotations, }, hosts: props?.ingress.hosts, tls: [ { hosts: props?.ingress.hosts, secretName: `tls-grafana-${name}`, }, ], }, deploymentStrategy: { type: 'Recreate', }, persistence: !props?.persistence ? { enabled: false } : { enabled: props?.persistence.enabled, size: pulumi.interpolate`${props?.persistence.sizeGB}Gi`, storageClass: props?.persistence.storageClass, }, testFramework: { enabled: false, }, 'grafana.ini': grafanaIni, datasources: { 'datasources.yaml': { apiVersion: 1, datasources: !props?.datasources ? [] : props?.datasources.map((datasource) => ({ name: datasource.name, type: datasource.type, url: datasource.url, access: 'proxy', basicAuth: false, editable: false, })), }, }, dashboards: !props?.dashboards ? undefined : { default: props?.dashboards.reduce((prev, curr) => { const { name, ...rest } = curr; return { ...prev, [name]: rest }; }, {}), }, dashboardProviders: !props?.dashboards ? undefined : { 'dashboardproviders.yaml': { apiVersion: 1, providers: [ { name: 'default', orgId: 1, folder: '', type: 'file', disableDeletion: false, editable: true, options: { path: '/var/lib/grafana/dashboards/default', }, }, ], }, }, plugins: props?.plugins, }, }, { parent: this, provider: props?.provider, } ); } }