blob: 4f8e904109caabc4b13b119519876202894c0e95 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 { IconNames } from '@blueprintjs/icons';
import React from 'react';
import { PluralPairIfNeeded } from '../../../components/plural-pair-if-needed/plural-pair-if-needed';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { lookupBy, queryDruidSql } from '../../../utils';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface ServiceCounts {
coordinator?: number;
overlord?: number;
router?: number;
broker?: number;
historical?: number;
middle_manager?: number;
peon?: number;
indexer?: number;
}
export interface ServicesCardProps {
capabilities: Capabilities;
}
export const ServicesCard = React.memo(function ServicesCard(props: ServicesCardProps) {
const [serviceCountState] = useQueryManager<Capabilities, ServiceCounts>({
processQuery: async capabilities => {
if (capabilities.hasSql()) {
const serviceCountsFromQuery: {
service_type: string;
count: number;
}[] = await queryDruidSql({
query: `SELECT server_type AS "service_type", COUNT(*) as "count" FROM sys.servers GROUP BY 1`,
});
return lookupBy(
serviceCountsFromQuery,
x => x.service_type,
x => x.count,
);
} else if (capabilities.hasCoordinatorAccess()) {
const services = (await Api.instance.get('/druid/coordinator/v1/servers?simple')).data;
const middleManager = capabilities.hasOverlordAccess()
? (await Api.instance.get('/druid/indexer/v1/workers')).data
: [];
return {
historical: services.filter((s: any) => s.type === 'historical').length,
middle_manager: middleManager.length,
peon: services.filter((s: any) => s.type === 'indexer-executor').length,
};
} else {
throw new Error(`must have SQL or coordinator access`);
}
},
initQuery: props.capabilities,
});
const serviceCounts = serviceCountState.data;
return (
<HomeViewCard
className="services-card"
href={'#services'}
icon={IconNames.DATABASE}
title={'Services'}
loading={serviceCountState.loading}
error={serviceCountState.error}
>
<PluralPairIfNeeded
firstCount={serviceCounts ? serviceCounts.overlord : 0}
firstSingular="overlord"
secondCount={serviceCounts ? serviceCounts.coordinator : 0}
secondSingular="coordinator"
/>
<PluralPairIfNeeded
firstCount={serviceCounts ? serviceCounts.router : 0}
firstSingular="router"
secondCount={serviceCounts ? serviceCounts.broker : 0}
secondSingular="broker"
/>
<PluralPairIfNeeded
firstCount={serviceCounts ? serviceCounts.historical : 0}
firstSingular="historical"
secondCount={serviceCounts ? serviceCounts.middle_manager : 0}
secondSingular="middle manager"
/>
<PluralPairIfNeeded
firstCount={serviceCounts ? serviceCounts.peon : 0}
firstSingular="peon"
secondCount={serviceCounts ? serviceCounts.indexer : 0}
secondSingular="indexer"
/>
</HomeViewCard>
);
});