/**
 * Copyright 2020 Opstrace, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ import { call , delay , select , CallEffect } from "redux-saga/effects" ; import { equals } from "ramda" ; import { KubeConfig } from "@kubernetes/client-node" ; import { set as updateTenants , Tenants } from "@opstrace/tenants" ; import dbClient , { ClientResponse } from "../dbClient" ; import { State } from "../reducer" ; import { log , SECOND } from "@opstrace/utils" ; import axios , { AxiosResponse } from "axios" ; const alertmanagerEndpoint = process . env . ALERTMANAGER_ENDPOINT ?? "" ; function * setDefaultAlertmanagerConfigIfEmpty ( endpoint , tenant ) { try { const res = yield axios ( { url : endpoint , method : "GET" , headers : { "X-Scope-OrgID" : tenant } } ) ; if ( res . status === 200 ) { return ; } } catch ( err ) { if ( ! err . response ) { log . error ( `could not read alertmanager config for tenant: ${ tenant }, got unknown error: %s` , err ) ; return ; } if ( err . response . status != 404 ) { log . error ( `could not read alertmanager config for tenant: ${ tenant }, got resp: ${ err . response . status }, ${ err . response . data . slice ( 0 , 500 ) }...` ) ; return ; } } try { yield axios ( { url : endpoint , method : "POST" , headers : { "X-Scope-OrgID" : tenant } , data : `alertmanager_config: |
  route:
    receiver: default-receiver
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    group_by: [alertname]
  receivers:
    - name: default-receiver
` } ) ; log . info ( `successfully set default alertmanager config ${ tenant } tenant` ) ; } catch ( err ) { log . error ( `could not write default alertmanager config to ${ tenant } tenant: %s` , err ) ; } } export function * syncTenants ( kubeConfig ) { return yield call ( function * ( ) { if ( ! dbClient ) { log . warning ( "exiting tenant sync due to missing env vars GRAPHQL_ENDPOINT & HASURA_GRAPHQL_ADMIN_SECRET" ) ; return ; } while ( true ) { try { const state = yield select ( ) ; const configmapTenants = state . tenants . list . tenants ; const res = yield call ( dbClient . GetTenants ) ; const dbTenants = res . data ?. tenant ; if ( ! dbTenants ) { throw Error ( "res.data.tenant doesn't exist in response" ) ; } if ( dbTenants . length === 0 ) { log . info ( "no tenants found in db, syncing existing tenants to db: %s" , JSON . stringify ( configmapTenants ) ) ; const tenants = configmapTenants . map ( t => ( { name : t . name , type : t . type , id : t . id } ) ) ; yield call ( dbClient . CreateTenants , { tenants } ) ; } else { const dbTenantsState = dbTenants . map ( t => ( { name : t . name , id : t . id , type : t . type === "SYSTEM" ? "SYSTEM" : "USER" } ) ) . sort ( ( t1 , t2 ) => t1 . name . localeCompare ( t2 . name ) ) as Tenants ; if ( ! equals ( dbTenantsState , configmapTenants ) ) { log . info ( "tenant config changed in db: old=%s new=%s" , JSON . stringify ( configmapTenants ) , JSON . stringify ( dbTenantsState ) ) ; yield call ( updateTenants , dbTenantsState , kubeConfig ) ; } if ( alertmanagerEndpoint !== "" ) { for ( const tenant of dbTenantsState ) { yield call ( setDefaultAlertmanagerConfigIfEmpty , alertmanagerEndpoint , tenant . name ) ; } } } } catch ( err ) { log . error ( "could not read/write from/to db during tenant sync, retrying in 5s: %s" , err ) ; } yield delay ( 5 * SECOND ) ; } } ) ; }