Skip to content

Commit

Permalink
HPA Sidebar content
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewballantyne committed Jul 29, 2020
1 parent e45e681 commit 1b007a6
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 22 deletions.
12 changes: 12 additions & 0 deletions frontend/packages/console-app/src/actions/modify-hpa.ts
Expand Up @@ -71,3 +71,15 @@ export const DeleteHorizontalPodAutoScaler: KebabAction = (
verb: 'delete',
},
});

export const hideActionForHPAs = (action: KebabAction): KebabAction => (
kind: K8sKind,
obj: K8sResourceCommon,
resources: RelatedResources,
) => {
const actionOptions = action(kind, obj);
return {
...actionOptions,
hidden: hasHPAs(resources) || actionOptions.hidden,
};
};
15 changes: 12 additions & 3 deletions frontend/packages/console-shared/src/components/pod/PodRing.tsx
Expand Up @@ -3,7 +3,8 @@ import * as _ from 'lodash';
import { Button, Split, SplitItem, Bullseye } from '@patternfly/react-core';
import { K8sResourceKind, k8sPatch, K8sKind } from '@console/internal/module/k8s';
import { AngleUpIcon, AngleDownIcon } from '@patternfly/react-icons';
import { podRingLabel, usePodScalingAccessStatus } from '../../utils';
import { useRelatedHPA } from '@console/dev-console/src/components/hpa/hooks';
import { hpaPodRingLabel, podRingLabel, usePodScalingAccessStatus } from '../../utils';
import { ExtPodKind } from '../../types';
import PodStatus from './PodStatus';
import './PodRing.scss';
Expand All @@ -28,7 +29,7 @@ const PodRing: React.FC<PodRingProps> = ({
enableScaling = true,
}) => {
const [clickCount, setClickCount] = React.useState(obj.spec.replicas);
const isScalingAllowed = usePodScalingAccessStatus(
const isAccessScalingAllowed = usePodScalingAccessStatus(
obj,
resourceKind,
pods,
Expand Down Expand Up @@ -67,8 +68,16 @@ const PodRing: React.FC<PodRingProps> = ({
setClickCount(clickCount + operation);
handleScaling(clickCount + operation);
};

const [hpa] = useRelatedHPA(obj.apiVersion, obj.kind, obj.metadata.name, obj.metadata.namespace);
const hpaControlledScaling = !!hpa;

const isScalingAllowed = isAccessScalingAllowed && !hpaControlledScaling;

const resourceObj = rc || obj;
const { title, subTitle, titleComponent } = podRingLabel(resourceObj, obj.kind, pods);
const { title, subTitle, titleComponent } = hpaControlledScaling
? hpaPodRingLabel(resourceObj, hpa, pods)
: podRingLabel(resourceObj, obj.kind, pods);

return (
<Split>
Expand Down
18 changes: 18 additions & 0 deletions frontend/packages/console-shared/src/utils/pod-ring-utils.ts
Expand Up @@ -16,6 +16,7 @@ import {
K8sResourceKind,
K8sKind,
SelfSubjectAccessReviewKind,
HorizontalPodAutoscalerKind,
} from '@console/internal/module/k8s';
import { useSafetyFirst } from '@console/internal/components/safety-first';
import { PodRCData, PodRingResources, PodRingData, ExtPodKind } from '../types';
Expand Down Expand Up @@ -206,6 +207,23 @@ export const podRingLabel = (
}
};

export const hpaPodRingLabel = (
obj: K8sResourceKind,
hpa: HorizontalPodAutoscalerKind,
pods: ExtPodKind[],
): PodRingLabelType => {
const desiredPodCount = obj.spec?.replicas;
const desiredPods = hpa.status?.desiredReplicas || desiredPodCount;
const currentPods = hpa.status?.currentReplicas;
const scaling =
(!currentPods && !!desiredPods) || !pods.every((p) => p.status?.phase === 'Running');
return {
title: scaling ? 'Autoscaling' : 'Autoscaled',
subTitle: `to ${desiredPods}`,
titleComponent: getTitleComponent(false, true),
};
};

export const usePodScalingAccessStatus = (
obj: K8sResourceKind,
resourceKind: K8sKind,
Expand Down
9 changes: 8 additions & 1 deletion frontend/packages/dev-console/src/components/hpa/HPAPage.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { Helmet } from 'react-helmet';
import { PageBody } from '@console/shared';
import { ErrorPage404 } from '@console/internal/components/error';
import { LoadingBox, LoadingInline, PageComponentProps } from '@console/internal/components/utils';
import { useK8sWatchResource } from '@console/internal/components/utils/k8s-watch-hook';
import { getGroupVersionKind, K8sResourceKind } from '@console/internal/module/k8s';
Expand All @@ -17,7 +18,8 @@ const HPAPage: React.FC<PageComponentProps> = (props) => {
params: { ns, resourceRef, name },
},
} = props;
const [group, version, kind] = getGroupVersionKind(resourceRef);
const breakdown = getGroupVersionKind(resourceRef) || [];
const [group, version, kind] = breakdown;
const [hpa, hpaLoaded, hpaError] = useRelatedHPA(`${group}/${version}`, kind, name, ns);
const resource = React.useMemo(
() => ({
Expand All @@ -34,6 +36,11 @@ const HPAPage: React.FC<PageComponentProps> = (props) => {

const validSupportedType = VALID_HPA_TARGET_KINDS.includes(kind);
const title = `${hpa ? 'Edit' : 'Add'} ${HorizontalPodAutoscalerModel.label}`;

if (!breakdown) {
return <ErrorPage404 />;
}

return (
<NamespacedPage disabled variant={NamespacedPageVariants.light} hideApplications>
<Helmet>
Expand Down
39 changes: 26 additions & 13 deletions frontend/packages/dev-console/src/components/hpa/hooks.ts
@@ -1,6 +1,8 @@
import * as React from 'react';
import { HorizontalPodAutoscalerKind, k8sList } from '@console/internal/module/k8s';
import { HorizontalPodAutoscalerModel } from '@console/internal/models';
import { doesHpaMatch } from './hpa-utils';
import { useK8sWatchResource } from '@console/internal/components/utils/k8s-watch-hook';

export const useRelatedHPA = (
workloadAPI: string,
Expand All @@ -10,26 +12,23 @@ export const useRelatedHPA = (
): [HorizontalPodAutoscalerKind, boolean, string] => {
const [loaded, setLoaded] = React.useState<boolean>(false);
const [errorMessage, setErrorMessage] = React.useState<string>(null);
const [hpa, setHPA] = React.useState<HorizontalPodAutoscalerKind>(null);
const [hpaName, setHPAName] = React.useState<string>(null);

React.useEffect(() => {
k8sList(HorizontalPodAutoscalerModel, { ns: workloadNamespace })
.then((hpaList: HorizontalPodAutoscalerKind[]) => {
const matchingHPA = hpaList.find((thisHPA: HorizontalPodAutoscalerKind) => {
const ref = thisHPA.spec.scaleTargetRef;
return (
ref.apiVersion === workloadAPI && ref.kind === workloadKind && ref.name === workloadName
);
});
const matchingHPA = hpaList.find(
doesHpaMatch({
apiVersion: workloadAPI,
kind: workloadKind,
metadata: { name: workloadName },
}),
);
setLoaded(true);
if (!matchingHPA) {
return;
}
setHPA({
apiVersion: `${HorizontalPodAutoscalerModel.apiGroup}/${HorizontalPodAutoscalerModel.apiVersion}`,
kind: HorizontalPodAutoscalerModel.kind,
...matchingHPA,
});
setHPAName(matchingHPA.metadata.name);
})
.catch((error) => {
setLoaded(true);
Expand All @@ -39,5 +38,19 @@ export const useRelatedHPA = (
});
}, [workloadAPI, workloadKind, workloadName, workloadNamespace]);

return [hpa, loaded, errorMessage];
const resource = React.useMemo(
() =>
hpaName && {
kind: HorizontalPodAutoscalerModel.kind,
name: hpaName,
namespace: workloadNamespace,
},
[hpaName, workloadNamespace],
);
const [hpa, hpaWatchLoaded, error] = useK8sWatchResource<HorizontalPodAutoscalerKind>(resource);

const returnHPA = !error && hpaName && loaded ? hpa : null;
const hpaLoaded = loaded && hpaWatchLoaded;
const hpaError = error || errorMessage;
return [returnHPA, hpaLoaded, hpaError];
};
Expand Up @@ -3,6 +3,7 @@ import { safeJSToYAML, safeYAMLToJS } from '@console/shared/src/utils/yaml';
import {
HorizontalPodAutoscalerKind,
HPAMetric,
K8sResourceCommon,
K8sResourceKind,
referenceForModel,
} from '@console/internal/module/k8s';
Expand Down Expand Up @@ -160,7 +161,7 @@ export const getInvalidUsageError = (
return null;
};

export const doesHpaMatch = (workload: K8sResourceKind) => (
export const doesHpaMatch = (workload: K8sResourceCommon) => (
thisHPA: HorizontalPodAutoscalerKind,
) => {
const workloadAPI: string = workload.apiVersion;
Expand Down
Expand Up @@ -6,8 +6,10 @@ import {
getPodData,
podRingLabel,
podDataInProgress,
hpaPodRingLabel,
} from '@console/shared';
import { DonutStatusData } from '../../topology-types';
import { useRelatedHPA } from '../../../hpa/hooks';

interface PodSetProps {
size: number;
Expand Down Expand Up @@ -67,8 +69,18 @@ const PodSet: React.FC<PodSetProps> = ({ size, data, x = 0, y = 0, showPodCount
data.isRollingOut,
);

const [hpa] = useRelatedHPA(
data.dc.apiVersion,
data.dc.kind,
data.dc.metadata.name,
data.dc.metadata.namespace,
);
const hpaControlledScaling = !!hpa;

const obj = get(data, ['current', 'obj'], null) || data.dc;
const { title, subTitle, titleComponent } = podRingLabel(obj, data.dc.kind, data?.pods);
const { title, subTitle, titleComponent } = hpaControlledScaling
? hpaPodRingLabel(obj, hpa, data?.pods)
: podRingLabel(obj, obj.kind, data?.pods);
return (
<>
<PodStatus
Expand Down
3 changes: 2 additions & 1 deletion frontend/public/components/deployment-config.tsx
Expand Up @@ -8,6 +8,7 @@ import {
AddHorizontalPodAutoScaler,
DeleteHorizontalPodAutoScaler,
EditHorizontalPodAutoScaler,
hideActionForHPAs,
} from '@console/app/src/actions/modify-hpa';
import { k8sCreate, K8sKind, K8sResourceKind, K8sResourceKindReference } from '../module/k8s';
import { errorModal } from './modals';
Expand Down Expand Up @@ -87,7 +88,7 @@ const { ModifyCount, AddStorage, common } = Kebab.factory;
export const menuActions: KebabAction[] = [
RolloutAction,
PauseAction,
ModifyCount,
hideActionForHPAs(ModifyCount),
AddHealthChecks,
AddHorizontalPodAutoScaler,
EditHorizontalPodAutoScaler,
Expand Down
3 changes: 2 additions & 1 deletion frontend/public/components/deployment.tsx
Expand Up @@ -7,6 +7,7 @@ import {
AddHorizontalPodAutoScaler,
DeleteHorizontalPodAutoScaler,
EditHorizontalPodAutoScaler,
hideActionForHPAs,
} from '@console/app/src/actions/modify-hpa';
import { DeploymentModel } from '../models';
import { DeploymentKind, K8sKind, K8sResourceKindReference } from '../module/k8s';
Expand Down Expand Up @@ -60,7 +61,7 @@ const PauseAction: KebabAction = (kind: K8sKind, obj: DeploymentKind) => ({
});

export const menuActions = [
ModifyCount,
hideActionForHPAs(ModifyCount),
PauseAction,
AddHealthChecks,
AddHorizontalPodAutoScaler,
Expand Down
31 changes: 31 additions & 0 deletions frontend/public/components/overview/hpa-overview.tsx
@@ -0,0 +1,31 @@
import * as React from 'react';
import { HorizontalPodAutoscalerKind } from '../../module/k8s';
import { ResourceLink, SidebarSectionHeading } from '../utils';
import { HorizontalPodAutoscalerModel } from '../../models';

type HPAOverviewProps = {
hpas?: HorizontalPodAutoscalerKind[];
};

export const HPAOverview: React.FC<HPAOverviewProps> = ({ hpas }) => {
if (!hpas?.length) {
return null;
}

return (
<div>
<SidebarSectionHeading text={HorizontalPodAutoscalerModel.labelPlural} />
<ul className="list-group">
{hpas.map((hpa: HorizontalPodAutoscalerKind) => (
<li key={hpa.metadata.name} className="list-group-item">
<ResourceLink
kind={HorizontalPodAutoscalerModel.kind}
name={hpa.metadata.name}
namespace={hpa.metadata.namespace}
/>
</li>
))}
</ul>
</div>
);
};
Expand Up @@ -10,6 +10,7 @@ import OperatorBackedOwnerReferences, {
} from '../utils';

import { BuildOverview } from './build-overview';
import { HPAOverview } from './hpa-overview';
import { NetworkingOverview } from './networking-overview';
import { PodsOverview } from './pods-overview';
import { resourceOverviewPages } from './resource-overview-pages';
Expand All @@ -20,13 +21,14 @@ const { common } = Kebab.factory;
export const OverviewDetailsResourcesTab: React.SFC<OverviewDetailsResourcesTabProps> = ({
item,
}) => {
const { buildConfigs, routes, services, pods, obj } = item;
const { buildConfigs, hpas, routes, services, pods, obj } = item;
const pluginComponents = usePluginsOverviewTabSection(item);
return (
<div className="overview__sidebar-pane-body">
<OperatorBackedOwnerReferences item={item} />
<PodsOverview pods={pods} obj={obj} />
<BuildOverview buildConfigs={buildConfigs} />
<HPAOverview hpas={hpas} />
{pluginComponents.map(({ Component, key }) => (
<Component key={key} item={item} />
))}
Expand Down
6 changes: 6 additions & 0 deletions frontend/public/module/k8s/types.ts
Expand Up @@ -385,6 +385,12 @@ export type HorizontalPodAutoscalerKind = K8sResourceCommon & {
maxReplicas: number;
metrics?: HPAMetric[];
};
status?: {
currentReplicas: number;
desiredReplicas: number;
currentMetrics: any;
conditions: NodeCondition[];
};
};

export type StorageClassResourceKind = {
Expand Down

0 comments on commit 1b007a6

Please sign in to comment.