Skip to content

feat: resource recommender #796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/Assets/IconV2/ic-container-registry.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 2 additions & 18 deletions src/Assets/IconV2/ic-container.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/Assets/IconV2/ic-gavel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/Assets/IconV2/ic-minus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/Assets/IconV2/ic-speedometer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/Assets/IconV2/ic-two-cubes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/Common/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const URLS = {
// NOTE: using appId since we are re-using AppConfig component
GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP_DETAIL: `${GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP}/detail/:appId`,
LICENSE_AUTH: '/license-auth',
GLOBAL_CONFIG_EDIT_CLUSTER: '/global-config/cluster-env/edit/:clusterId',
} as const

export const ROUTES = {
Expand Down Expand Up @@ -381,6 +382,7 @@ export const API_STATUS_CODES = {
NOT_FOUND: 404,
REQUEST_TIMEOUT: 408,
CONFLICT: 409,
PRE_CONDITION_FAILED: 412,
EXPECTATION_FAILED: 417,
UNPROCESSABLE_ENTITY: 422,
LOCKED: 423,
Expand Down
4 changes: 4 additions & 0 deletions src/Common/RJSF/rjsfForm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

input.form__input {
padding: 6px 8px;

&[readonly] {
opacity: 0.5;
}
}
}

Expand Down
74 changes: 72 additions & 2 deletions src/Pages/ResourceBrowser/ResourceBrowser.Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
* limitations under the License.
*/

import { RefObject } from 'react'
import { Dispatch, RefObject, SetStateAction } from 'react'
import { GroupBase } from 'react-select'

import { ServerErrors } from '@Common/ServerError'
import { SelectPickerOptionType } from '@Shared/Components'
import { Nodes, NodeType } from '@Shared/types'

export interface GVKType {
Expand Down Expand Up @@ -59,8 +62,54 @@ export interface K8sResourceListPayloadType {
k8sRequest: ResourceListPayloadK8sRequestType
}

export enum ResourceRecommenderHeaderType {
NAME = 'name',
NAMESPACE = 'namespace',
KIND = 'kind',
API_VERSION = 'apiVersion',
CONTAINER_NAME = 'containerName',
CPU_REQUEST = 'cpuRequest',
CPU_LIMIT = 'cpuLimit',
MEMORY_REQUEST = 'memoryRequest',
MEMORY_LIMIT = 'memoryLimit',
}

export type ResourceRecommenderHeaderWithStringValue = Extract<
ResourceRecommenderHeaderType,
| ResourceRecommenderHeaderType.NAME
| ResourceRecommenderHeaderType.NAMESPACE
| ResourceRecommenderHeaderType.KIND
| ResourceRecommenderHeaderType.API_VERSION
| ResourceRecommenderHeaderType.CONTAINER_NAME
>

export type ResourceRecommenderHeaderWithRecommendation = Extract<
ResourceRecommenderHeaderType,
| ResourceRecommenderHeaderType.CPU_REQUEST
| ResourceRecommenderHeaderType.CPU_LIMIT
| ResourceRecommenderHeaderType.MEMORY_REQUEST
| ResourceRecommenderHeaderType.MEMORY_LIMIT
>

export type K8sResourceDetailDataType = {
[key: string]: string | number | object | boolean
additionalMetadata?: Partial<
Record<
ResourceRecommenderHeaderWithRecommendation,
{
// In case there is not limit or request set, it will be null
current: {
value: string | 'none'
} | null
// In case cron is yet to run
recommended: {
value: string | 'none'
} | null
// In case any of current or recommended is null, delta will be null
delta: number | null
}
>
>
}

export interface K8sResourceDetailType {
Expand All @@ -69,19 +118,21 @@ export interface K8sResourceDetailType {
}

export interface BulkSelectionActionWidgetProps {
isResourceRecommendationView: boolean
count: number
handleOpenBulkDeleteModal: () => void
handleClearBulkSelection: () => void
handleOpenCordonNodeModal: () => void
handleOpenUncordonNodeModal: () => void
handleOpenDrainNodeModal: () => void
handleOpenRestartWorkloadModal: () => void
handleOpenApplyResourceRecommendationModal: () => void
parentRef: RefObject<HTMLDivElement>
showBulkRestartOption: boolean
showNodeListingOptions: boolean
}

export type RBBulkOperationType = 'restart' | 'delete' | 'cordon' | 'uncordon' | 'drain'
export type RBBulkOperationType = 'restart' | 'delete' | 'cordon' | 'uncordon' | 'drain' | 'applyResourceRecommendation'

export interface CreateResourceRequestBodyType {
appId: string
Expand All @@ -95,6 +146,7 @@ export interface CreateResourceRequestBodyType {
export interface ResourceManifestDTO {
manifestResponse: {
manifest: Record<string, unknown>
recommendedManifest?: Record<string, unknown>
}
secretViewAccess: boolean
}
Expand Down Expand Up @@ -146,3 +198,21 @@ export interface NodeActionRequest {
version: string
kind: string
}

export interface GVKOptionValueType {
kind: string
apiVersion: string
}

export interface GetResourceRecommenderResourceListPropsType {
resourceList: K8sResourceDetailType
reloadResourceListData: () => void
setShowAbsoluteValuesInResourceRecommender: Dispatch<SetStateAction<boolean>>
showAbsoluteValuesInResourceRecommender: boolean
gvkOptions: GroupBase<SelectPickerOptionType<GVKOptionValueType>>[]
areGVKOptionsLoading: boolean
reloadGVKOptions: () => void
gvkOptionsError: ServerErrors
isResourceListLoading: boolean
resourceListError: ServerErrors
}
3 changes: 3 additions & 0 deletions src/Pages/ResourceBrowser/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,6 @@ export const NODE_DRAIN_OPTIONS_CHECKBOX_CONFIG: {
label: DRAIN_NODE_MODAL_MESSAGING.IgnoreDaemonSets.heading,
},
] as const

export const GVK_FILTER_KIND_QUERY_PARAM_KEY = 'gvkFilterKind'
export const GVK_FILTER_API_VERSION_QUERY_PARAM_KEY = 'gvkFilterApiVersion'
4 changes: 3 additions & 1 deletion src/Pages/ResourceBrowser/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export const getK8sResourceList = (

export const createNewResource = (
resourceListPayload: CreateResourcePayload,
): Promise<ResponseType<CreateResourceDTO[]>> => post(ROUTES.K8S_RESOURCE_CREATE, resourceListPayload)
abortControllerRef?: APIOptions['abortControllerRef'],
): Promise<ResponseType<CreateResourceDTO[]>> =>
post(ROUTES.K8S_RESOURCE_CREATE, resourceListPayload, { abortControllerRef })

export const deleteResource = (
resourceListPayload: ResourceListPayloadType,
Expand Down
8 changes: 8 additions & 0 deletions src/Shared/Components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { ReactComponent as ICCluster } from '@IconsV2/ic-cluster.svg'
import { ReactComponent as ICClusterIsolated } from '@IconsV2/ic-cluster-isolated.svg'
import { ReactComponent as ICCode } from '@IconsV2/ic-code.svg'
import { ReactComponent as ICContainer } from '@IconsV2/ic-container.svg'
import { ReactComponent as ICContainerRegistry } from '@IconsV2/ic-container-registry.svg'
import { ReactComponent as ICCookr } from '@IconsV2/ic-cookr.svg'
import { ReactComponent as ICCopy } from '@IconsV2/ic-copy.svg'
import { ReactComponent as ICCpu } from '@IconsV2/ic-cpu.svg'
Expand Down Expand Up @@ -84,6 +85,7 @@ import { ReactComponent as ICFilterApplied } from '@IconsV2/ic-filter-applied.sv
import { ReactComponent as ICFlask } from '@IconsV2/ic-flask.svg'
import { ReactComponent as ICFolderColor } from '@IconsV2/ic-folder-color.svg'
import { ReactComponent as ICFolderUser } from '@IconsV2/ic-folder-user.svg'
import { ReactComponent as ICGavel } from '@IconsV2/ic-gavel.svg'
import { ReactComponent as ICGear } from '@IconsV2/ic-gear.svg'
import { ReactComponent as ICGift } from '@IconsV2/ic-gift.svg'
import { ReactComponent as ICGiftGradient } from '@IconsV2/ic-gift-gradient.svg'
Expand Down Expand Up @@ -160,6 +162,7 @@ import { ReactComponent as ICSortDescending } from '@IconsV2/ic-sort-descending.
import { ReactComponent as ICSortable } from '@IconsV2/ic-sortable.svg'
import { ReactComponent as ICSparkleAiColor } from '@IconsV2/ic-sparkle-ai-color.svg'
import { ReactComponent as ICSparkleColor } from '@IconsV2/ic-sparkle-color.svg'
import { ReactComponent as ICSpeedometer } from '@IconsV2/ic-speedometer.svg'
import { ReactComponent as ICSpinny } from '@IconsV2/ic-spinny.svg'
import { ReactComponent as ICSprayCan } from '@IconsV2/ic-spray-can.svg'
import { ReactComponent as ICStack } from '@IconsV2/ic-stack.svg'
Expand All @@ -186,6 +189,7 @@ import { ReactComponent as ICTimeoutDash } from '@IconsV2/ic-timeout-dash.svg'
import { ReactComponent as ICTimer } from '@IconsV2/ic-timer.svg'
import { ReactComponent as ICTrafficSignal } from '@IconsV2/ic-traffic-signal.svg'
import { ReactComponent as ICTravclan } from '@IconsV2/ic-travclan.svg'
import { ReactComponent as ICTwoCubes } from '@IconsV2/ic-two-cubes.svg'
import { ReactComponent as ICUbuntu } from '@IconsV2/ic-ubuntu.svg'
import { ReactComponent as ICUnknown } from '@IconsV2/ic-unknown.svg'
import { ReactComponent as ICUserCircle } from '@IconsV2/ic-user-circle.svg'
Expand Down Expand Up @@ -245,6 +249,7 @@ export const iconMap = {
'ic-cluster-isolated': ICClusterIsolated,
'ic-cluster': ICCluster,
'ic-code': ICCode,
'ic-container-registry': ICContainerRegistry,
'ic-container': ICContainer,
'ic-cookr': ICCookr,
'ic-copy': ICCopy,
Expand Down Expand Up @@ -285,6 +290,7 @@ export const iconMap = {
'ic-flask': ICFlask,
'ic-folder-color': ICFolderColor,
'ic-folder-user': ICFolderUser,
'ic-gavel': ICGavel,
'ic-gear': ICGear,
'ic-gift-gradient': ICGiftGradient,
'ic-gift': ICGift,
Expand Down Expand Up @@ -361,6 +367,7 @@ export const iconMap = {
'ic-sortable': ICSortable,
'ic-sparkle-ai-color': ICSparkleAiColor,
'ic-sparkle-color': ICSparkleColor,
'ic-speedometer': ICSpeedometer,
'ic-spinny': ICSpinny,
'ic-spray-can': ICSprayCan,
'ic-stack': ICStack,
Expand All @@ -387,6 +394,7 @@ export const iconMap = {
'ic-timer': ICTimer,
'ic-traffic-signal': ICTrafficSignal,
'ic-travclan': ICTravclan,
'ic-two-cubes': ICTwoCubes,
'ic-ubuntu': ICUbuntu,
'ic-unknown': ICUnknown,
'ic-user-circle': ICUserCircle,
Expand Down
Loading