2
0
Эх сурвалжийг харах

Merge branch 'master' of github.com:porter-dev/porter into 0.7.0-fix-5xx-metrics

jnfrati 4 жил өмнө
parent
commit
027a4022dc

+ 9 - 1
dashboard/src/components/porter-form/PorterForm.tsx

@@ -41,6 +41,7 @@ interface Props {
   showStateDebugger?: boolean;
   currentTab: string;
   setCurrentTab: (nt: string) => void;
+  isLaunch?: boolean;
 }
 
 const PorterForm: React.FC<Props> = (props) => {
@@ -102,11 +103,14 @@ const PorterForm: React.FC<Props> = (props) => {
     let options = (props.leftTabOptions || [])
       .concat(
         formData?.tabs?.map((tab) => {
+          if (props.isLaunch && tab?.settings?.omitFromLaunch) {
+            return undefined;
+          }
           return { label: tab.label, value: tab.name };
         })
       )
       .concat(props.rightTabOptions || []);
-    return options.filter((x) => x !== undefined);
+    return options.filter((x) => !!x);
   };
 
   const showSaveButton = (): boolean => {
@@ -131,10 +135,13 @@ const PorterForm: React.FC<Props> = (props) => {
 
   const renderTab = (): JSX.Element => {
     if (!formData) {
+      console.log("hm fuck");
       return props.renderTabContents(currentTab);
     }
 
     const tab = formData.tabs?.filter((tab) => tab.name == currentTab)[0];
+    console.log("currentTab", currentTab);
+    console.log("tab", tab);
 
     // Handle external tab
     if (!tab) {
@@ -173,6 +180,7 @@ const PorterForm: React.FC<Props> = (props) => {
     return props.saveValuesStatus;
   };
 
+  console.log(getTabOptions());
   return (
     <>
       <TabRegion

+ 44 - 12
dashboard/src/components/porter-form/PorterFormContextProvider.tsx

@@ -58,12 +58,15 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
               ...state.components,
               [action.id]: {
                 state: action.initValue,
-                validation: {
-                  ...{
-                    validated: false,
-                  },
-                  ...action.initValidation,
+              },
+            },
+            validation: {
+              ...state.validation,
+              [action.id]: {
+                ...{
+                  validated: false,
                 },
+                ...action.initValidation,
               },
             },
           };
@@ -94,9 +97,12 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
             ...state.components,
             [action.id]: {
               ...state.components[action.id],
-              validation: action.updateFunc(
-                state.components[action.id].validation
-              ),
+            },
+          },
+          validation: {
+            ...state.validation,
+            [action.id]: {
+              ...action.updateFunc(state.validation[action.id]),
             },
           },
         };
@@ -128,8 +134,36 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
     return ret;
   };
 
+  const getInitialValidation = (data: PorterFormData) => {
+    const ret: Record<string, any> = {};
+    data?.tabs?.map((tab, i) =>
+      tab.sections?.map((section, j) =>
+        section.contents?.map((field, k) => {
+          if (
+            field.type == "heading" ||
+            field.type == "subtitle" ||
+            field.type == "resource-list" ||
+            field.type == "service-ip-list" ||
+            field.type == "velero-create-backup"
+          )
+            return;
+          if (
+            field.required &&
+            (field.settings?.default || (field.value && field.value[0]))
+          ) {
+            ret[`${i}-${j}-${k}`] = {
+              validated: true,
+            };
+          }
+        })
+      )
+    );
+    return ret;
+  };
+
   const [state, dispatch] = useReducer(handleAction, {
     components: {},
+    validation: getInitialValidation(props.rawFormData),
     variables: {
       ...props.initialVariables,
       ...getInitialVariables(props.rawFormData),
@@ -310,7 +344,7 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
             return;
           // fields that have defaults can't be required since we can always
           // compute their value
-          if (field.required && !field.settings?.default) {
+          if (field.required) {
             requiredIds.push(field.id);
           }
           if (!mapping[field.variable]) {
@@ -327,9 +361,7 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
     Validate the form based on a list of required ids
    */
   const doValidation = (requiredIds: string[]) =>
-    requiredIds
-      ?.map((id) => state.components[id]?.validation.validated)
-      .every((x) => x);
+    requiredIds?.map((id) => state.validation[id]?.validated).every((x) => x);
 
   const formData = computeFormStructure(
     restructureToNewFields(props.rawFormData),

+ 11 - 1
dashboard/src/components/porter-form/PorterFormWrapper.tsx

@@ -18,6 +18,7 @@ type PropsType = {
   addendum?: any;
   saveValuesStatus?: string;
   showStateDebugger?: boolean;
+  isLaunch?: boolean;
 };
 
 const PorterFormWrapper: React.FunctionComponent<PropsType> = ({
@@ -34,6 +35,7 @@ const PorterFormWrapper: React.FunctionComponent<PropsType> = ({
   addendum,
   saveValuesStatus,
   showStateDebugger,
+  isLaunch,
 }) => {
   const hashCode = (s: string) => {
     return s.split("").reduce(function (a, b) {
@@ -46,7 +48,13 @@ const PorterFormWrapper: React.FunctionComponent<PropsType> = ({
     if (leftTabOptions?.length > 0) {
       return leftTabOptions[0].value;
     } else if (formData?.tabs?.length > 0) {
-      return formData?.tabs[0].name;
+      let includedTabs = formData.tabs;
+      if (isLaunch) {
+        includedTabs = formData.tabs.filter(
+          (tab: any) => !tab?.settings?.omitFromLaunch
+        );
+      }
+      return includedTabs[0].name;
     } else if (rightTabOptions?.length > 0) {
       return rightTabOptions[0].value;
     } else {
@@ -54,6 +62,7 @@ const PorterFormWrapper: React.FunctionComponent<PropsType> = ({
     }
   };
 
+  // Lifted into PorterFormWrapper to allow tab to be remembered on re-render (e.g., on revision select)
   const [currentTab, setCurrentTab] = useState(getInitialTab());
 
   return (
@@ -77,6 +86,7 @@ const PorterFormWrapper: React.FunctionComponent<PropsType> = ({
           saveValuesStatus={saveValuesStatus}
           currentTab={currentTab}
           setCurrentTab={setCurrentTab}
+          isLaunch={isLaunch}
         />
       </PorterFormContextProvider>
     </React.Fragment>

+ 18 - 15
dashboard/src/components/porter-form/field-components/Input.tsx

@@ -8,6 +8,15 @@ import {
   StringInputFieldState,
 } from "../types";
 
+const clipOffUnit = (unit: string, x: string) => {
+  if (typeof x === "string" && unit) {
+    return unit === x.slice(x.length - unit.length, x.length)
+      ? x.slice(0, x.length - unit.length)
+      : x;
+  }
+  return x;
+};
+
 const Input: React.FC<InputField> = ({
   id,
   variable,
@@ -19,18 +28,6 @@ const Input: React.FC<InputField> = ({
   isReadOnly,
   value,
 }) => {
-  const clipOffUnit = (x: string) => {
-    let unit = settings?.unit;
-    if (typeof x === "string" && unit) {
-      return unit === x.slice(x.length - unit.length, x.length) ? (
-        x.slice(0, x.length - unit.length)
-      ) : (
-        x
-      );
-    }
-    return x;
-  }
-
   const {
     state,
     variables,
@@ -39,11 +36,13 @@ const Input: React.FC<InputField> = ({
   } = useFormField<StringInputFieldState>(id, {
     initValidation: {
       validated: value
-        ? value[0] !== undefined
+        ? value[0] !== undefined && value[0] !== ""
         : settings?.default != undefined,
     },
     initVars: {
-      [variable]: value ? clipOffUnit(value[0]) : settings?.default,
+      [variable]: value
+        ? clipOffUnit(settings?.unit, value[0])
+        : settings?.default,
     },
   });
 
@@ -94,7 +93,11 @@ export const getFinalVariablesForStringInput: GetFinalVariablesFunction = (
   vars,
   props: InputField
 ) => {
-  const val = vars[props.variable] || props.settings?.default;
+  const val =
+    vars[props.variable] ||
+    (props.value
+      ? clipOffUnit(props.settings?.unit, props.value[0])
+      : props.settings?.default);
   return {
     [props.variable]:
       props.settings?.unit && !props.settings.omitUnitFromValue

+ 1 - 2
dashboard/src/components/porter-form/field-components/KeyValueArray.tsx

@@ -138,10 +138,9 @@ const KeyValueArray: React.FC<Props> = (props) => {
       obj[key] = value;
     });
     return obj;
-  }
+  };
 
   const renderEnvModal = () => {
-    console.log(state.values)
     if (state.showEnvModal) {
       return (
         <Modal

+ 6 - 1
dashboard/src/components/porter-form/types.ts

@@ -145,6 +145,9 @@ export interface Tab {
   name: string;
   label: string;
   sections: Section[];
+  settings?: {
+    omitFromLaunch?: boolean;
+  };
 }
 
 export interface PorterFormData {
@@ -194,9 +197,11 @@ export interface PorterFormState {
   components: {
     [key: string]: {
       state: PorterFormFieldFieldState;
-      validation: PorterFormFieldValidationState;
     };
   };
+  validation: {
+    [key: string]: PorterFormFieldValidationState;
+  };
   variables: PorterFormVariableList;
 }
 

+ 11 - 13
dashboard/src/main/home/Home.tsx

@@ -485,9 +485,9 @@ class Home extends Component<PropsType, StateType> {
   };
 
   render() {
-    let { 
-      currentModal, 
-      setCurrentModal, 
+    let {
+      currentModal,
+      setCurrentModal,
       currentProject,
       currentOverlay,
       setCurrentOverlay,
@@ -578,16 +578,14 @@ class Home extends Component<PropsType, StateType> {
           </Modal>
         )}
 
-        {
-          currentOverlay && (
-            <ConfirmOverlay
-              show={true}
-              message={currentOverlay.message}
-              onYes={currentOverlay.onYes}
-              onNo={currentOverlay.onNo}
-            />
-          )
-        }
+        {currentOverlay && (
+          <ConfirmOverlay
+            show={true}
+            message={currentOverlay.message}
+            onYes={currentOverlay.onYes}
+            onNo={currentOverlay.onNo}
+          />
+        )}
 
         {this.renderSidebar()}
 

+ 24 - 24
dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx

@@ -392,30 +392,30 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
             </LastDeployed>
           </InfoWrapper>
 
-          {
-            this.state.deleting ? (
-              <>
-                <LineBreak />
-                <Placeholder>
-                  <TextWrap>
-                    <Header>
-                      <Spinner src={loading} /> Deleting "{this.state.envGroup.name}"
-                    </Header>
-                    You will be automatically redirected after deletion is complete.
-                  </TextWrap>
-                </Placeholder>
-              </>
-            ) : (
-              <TabRegion
-                currentTab={this.state.currentTab}
-                setCurrentTab={(x: string) => this.setState({ currentTab: x })}
-                options={this.state.tabOptions}
-                color={null}
-              >
-                {this.renderTabContents()}
-              </TabRegion>
-            )
-          }
+          {this.state.deleting ? (
+            <>
+              <LineBreak />
+              <Placeholder>
+                <TextWrap>
+                  <Header>
+                    <Spinner src={loading} /> Deleting "
+                    {this.state.envGroup.name}"
+                  </Header>
+                  You will be automatically redirected after deletion is
+                  complete.
+                </TextWrap>
+              </Placeholder>
+            </>
+          ) : (
+            <TabRegion
+              currentTab={this.state.currentTab}
+              setCurrentTab={(x: string) => this.setState({ currentTab: x })}
+              options={this.state.tabOptions}
+              color={null}
+            >
+              {this.renderTabContents()}
+            </TabRegion>
+          )}
         </StyledExpandedChart>
       </>
     );

+ 67 - 64
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -89,9 +89,9 @@ const ExpandedChart: React.FC<Props> = (props) => {
     closeWebsocket,
   } = useWebsockets();
 
-  const { 
-    currentCluster, 
-    currentProject, 
+  const {
+    currentCluster,
+    currentProject,
     setCurrentError,
     setCurrentOverlay,
   } = useContext(Context);
@@ -468,7 +468,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
         (tab: any) => !liveTabs.includes(tab.value)
       );
     }
-    
+
     setLeftTabOptions(leftTabOptions);
     setRightTabOptions(rightTabOptions);
   };
@@ -693,66 +693,69 @@ const ExpandedChart: React.FC<Props> = (props) => {
             </LastDeployed>
           </InfoWrapper>
         </HeaderWrapper>
-        {
-          deleting ? (
-            <>
-              <LineBreak />
-              <Placeholder>
-                <TextWrap>
-                  <Header>
-                    <Spinner src={loadingSrc} /> Deleting "{currentChart.name}"
-                  </Header>
-                  You will be automatically redirected after deletion is complete.
-                </TextWrap>
-              </Placeholder>
-            </>
-          ) : (
-            <>
-              <RevisionSection
-                showRevisions={showRevisions}
-                toggleShowRevisions={() => {
-                  setShowRevisions(!showRevisions);
-                }}
-                chart={currentChart}
-                refreshChart={() => getChartData(currentChart)}
-                setRevision={setRevision}
-                forceRefreshRevisions={forceRefreshRevisions}
-                refreshRevisionsOff={() => setForceRefreshRevisions(false)}
-                status={chartStatus}
-                shouldUpdate={
-                  currentChart.latest_version &&
-                  currentChart.latest_version !== currentChart.chart.metadata.version
-                }
-                latestVersion={currentChart.latest_version}
-                upgradeVersion={handleUpgradeVersion}
-              />
-              <BodyWrapper>
-                <PorterFormWrapper
-                  formData={currentChart.form}
-                  valuesToOverride={{
-                    namespace: props.namespace,
-                    clusterId: currentCluster.id,
-                  }}
-                  renderTabContents={renderTabContents}
-                  isReadOnly={
-                    imageIsPlaceholder ||
-                    !isAuthorized("application", "", ["get", "update"])
-                  }
-                  onSubmit={onSubmit}
-                  rightTabOptions={rightTabOptions}
-                  leftTabOptions={leftTabOptions}
-                  color={isPreview ? "#f5cb42" : null}
-                  addendum={
-                    <TabButton onClick={toggleDevOpsMode} devOpsMode={devOpsMode}>
-                      <i className="material-icons">offline_bolt</i> DevOps Mode
-                    </TabButton>
-                  }
-                  saveValuesStatus={saveValuesStatus}
-                />
-              </BodyWrapper>
-            </>
-          )
-        }
+        {deleting ? (
+          <>
+            <LineBreak />
+            <Placeholder>
+              <TextWrap>
+                <Header>
+                  <Spinner src={loadingSrc} /> Deleting "{currentChart.name}"
+                </Header>
+                You will be automatically redirected after deletion is complete.
+              </TextWrap>
+            </Placeholder>
+          </>
+        ) : (
+          <>
+            <RevisionSection
+              showRevisions={showRevisions}
+              toggleShowRevisions={() => {
+                setShowRevisions(!showRevisions);
+              }}
+              chart={currentChart}
+              refreshChart={() => getChartData(currentChart)}
+              setRevision={setRevision}
+              forceRefreshRevisions={forceRefreshRevisions}
+              refreshRevisionsOff={() => setForceRefreshRevisions(false)}
+              status={chartStatus}
+              shouldUpdate={
+                currentChart.latest_version &&
+                currentChart.latest_version !==
+                  currentChart.chart.metadata.version
+              }
+              latestVersion={currentChart.latest_version}
+              upgradeVersion={handleUpgradeVersion}
+            />
+            {
+              leftTabOptions.length > 0 && (
+                <BodyWrapper>
+                  <PorterFormWrapper
+                    formData={currentChart.form}
+                    valuesToOverride={{
+                      namespace: props.namespace,
+                      clusterId: currentCluster.id,
+                    }}
+                    renderTabContents={renderTabContents}
+                    isReadOnly={
+                      imageIsPlaceholder ||
+                      !isAuthorized("application", "", ["get", "update"])
+                    }
+                    onSubmit={onSubmit}
+                    rightTabOptions={rightTabOptions}
+                    leftTabOptions={leftTabOptions}
+                    color={isPreview ? "#f5cb42" : null}
+                    addendum={
+                      <TabButton onClick={toggleDevOpsMode} devOpsMode={devOpsMode}>
+                        <i className="material-icons">offline_bolt</i> DevOps Mode
+                      </TabButton>
+                    }
+                    saveValuesStatus={saveValuesStatus}
+                  />
+                </BodyWrapper>
+              )
+            }
+          </>
+        )}
       </StyledExpandedChart>
     </>
   );

+ 5 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChartWrapper.tsx

@@ -93,7 +93,11 @@ class ExpandedChartWrapper extends Component<PropsType, StateType> {
     let { baseRoute, namespace } = match.params as any;
     let { loading, currentChart } = this.state;
     if (loading) {
-      return <LoadingWrapper><Loading /></LoadingWrapper>;
+      return (
+        <LoadingWrapper>
+          <Loading />
+        </LoadingWrapper>
+      );
     } else if (currentChart && baseRoute === "jobs") {
       return (
         <ExpandedJobChart

+ 41 - 42
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -587,48 +587,47 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
             </InfoWrapper>
           </HeaderWrapper>
 
-          {
-            this.state.deleting ? (
-              <>
-                <LineBreak />
-                <Placeholder>
-                  <TextWrap>
-                    <Header>
-                      <Spinner src={loading} /> Deleting "{currentChart.name}"
-                    </Header>
-                    You will be automatically redirected after deletion is complete.
-                  </TextWrap>
-                </Placeholder>
-              </>
-            ) : (
-              <BodyWrapper>
-                {(this.state.leftTabOptions?.length > 0 ||
-                  this.state.formData.tabs?.length > 0 ||
-                  this.state.rightTabOptions?.length > 0) && (
-                  <PorterFormWrapper
-                    formData={this.state.formData}
-                    valuesToOverride={{
-                      namespace: chart.namespace,
-                      clusterId: this.props.currentCluster.id,
-                    }}
-                    renderTabContents={this.renderTabContents}
-                    isReadOnly={
-                      this.state.imageIsPlaceholder ||
-                      !this.props.isAuthorized("job", "", ["get", "update"])
-                    }
-                    onSubmit={(formValues) => {
-                      console.log(formValues)
-                      this.handleSaveValues(formValues, false)
-                    }}
-                    leftTabOptions={this.state.leftTabOptions}
-                    rightTabOptions={this.state.rightTabOptions}
-                    saveValuesStatus={this.state.saveValuesStatus}
-                    saveButtonText="Save Config"
-                  />
-                )}
-              </BodyWrapper>
-            )
-          }
+          {this.state.deleting ? (
+            <>
+              <LineBreak />
+              <Placeholder>
+                <TextWrap>
+                  <Header>
+                    <Spinner src={loading} /> Deleting "{currentChart.name}"
+                  </Header>
+                  You will be automatically redirected after deletion is
+                  complete.
+                </TextWrap>
+              </Placeholder>
+            </>
+          ) : (
+            <BodyWrapper>
+              {(this.state.leftTabOptions?.length > 0 ||
+                this.state.formData.tabs?.length > 0 ||
+                this.state.rightTabOptions?.length > 0) && (
+                <PorterFormWrapper
+                  formData={this.state.formData}
+                  valuesToOverride={{
+                    namespace: chart.namespace,
+                    clusterId: this.props.currentCluster.id,
+                  }}
+                  renderTabContents={this.renderTabContents}
+                  isReadOnly={
+                    this.state.imageIsPlaceholder ||
+                    !this.props.isAuthorized("job", "", ["get", "update"])
+                  }
+                  onSubmit={(formValues) => {
+                    console.log(formValues);
+                    this.handleSaveValues(formValues, false);
+                  }}
+                  leftTabOptions={this.state.leftTabOptions}
+                  rightTabOptions={this.state.rightTabOptions}
+                  saveValuesStatus={this.state.saveValuesStatus}
+                  saveButtonText="Save Config"
+                />
+              )}
+            </BodyWrapper>
+          )}
         </StyledExpandedChart>
       </>
     );

+ 4 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx

@@ -188,6 +188,10 @@ const MetricsSection: React.FunctionComponent<PropsType> = ({
 
     setIsLoading((prev) => prev + 1);
 
+    if (selectors[0] === "") {
+      return;
+    }
+
     api
       .getMatchingPods(
         "<token>",

+ 1 - 3
dashboard/src/main/home/launch/launch-flow/SettingsPage.tsx

@@ -151,9 +151,7 @@ class SettingsPage extends Component<PropsType, StateType> {
               namespace: selectedNamespace,
               clusterId: this.context.currentCluster.id,
             }}
-            //externalValues={{
-            //  isLaunch: true,
-            //}}
+            isLaunch={true}
             isReadOnly={
               !this.props.isAuthorized("namespace", "", ["get", "create"])
             }

+ 3 - 3
dashboard/src/shared/Context.tsx

@@ -26,9 +26,9 @@ export interface GlobalContextType {
   currentModalData: any;
   setCurrentModal: (currentModal: string, currentModalData?: any) => void;
   currentOverlay: {
-    message: string,
-    onYes: any,
-    onNo: any,
+    message: string;
+    onYes: any;
+    onNo: any;
   };
   setCurrentOverlay: (x: any) => void;
   currentError: string | null;

+ 3 - 3
dashboard/src/shared/types.tsx

@@ -267,9 +267,9 @@ export interface ContextProps {
   currentModalData: any;
   setCurrentModal: (currentModal: string, currentModalData?: any) => void;
   currentOverlay: {
-    message: string,
-    onYes: any,
-    onNo: any,
+    message: string;
+    onYes: any;
+    onNo: any;
   };
   setCurrentOverlay: (x: any) => void;
   currentError?: string;

+ 18 - 0
docs/developing/test-autoscaling.md

@@ -0,0 +1,18 @@
+# Test Cluster and HPA Autoscaling
+
+Prerequisites: 
+- [`metrics-server`](https://artifacthub.io/packages/helm/bitnami/metrics-server) must be installed (installed by default on all Porter clusters). 
+- [`cluster-autoscaler`](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler) must be enabled (enabled by default on all Porter clusters). 
+- Have `kubectl` access to the cluster, as it is easiest to port-forward to the exposed service. 
+- Download [`hey`](https://github.com/rakyll/hey) or an equivalent. 
+
+# Steps
+
+1. Launch a Docker template with image URL `k8s.gcr.io/hpa-example`. Enable autoscaling under the **Resources** tab -- suggested params are 100 Mi RAM, 100m CPU, 1-100 replicas, 50% CPU & RAM util. Do not **Expose to external traffic** to run load tests.
+
+2. Confirm that the horizontal pod autoscaler was created via kubectl (`kubectl get hpa`) and that the metrics server is reporting metrics via `kubectl top pods`. Current utilization may initially show up as `<undefined>`, but this information should load after a minute or so.
+
+3. Port-forward to the service via `kubectl port-forward svc/<svc-name> 10000:80`. 
+4. In a different terminal window, run `hey http://localhost:10000`. Vary the `hey` parameters to test autoscaling under different loads (`hey -h` for options). 
+
+Check that replicas scale when passing the threshold from the metrics tab. Use kubectl to probe the nodes and confirm cluster-level upscaling has also occurred. Delete the chart and confirm node downscaling when done.

+ 114 - 21
internal/kubernetes/prometheus/metrics.go

@@ -126,7 +126,8 @@ func QueryPrometheus(
 		query = fmt.Sprintf(`%s / %s * 100 OR on() vector(0)`, num, denom)
 	} else if opts.Metric == "cpu_hpa_threshold" {
 		// get the name of the kube hpa metric
-		metricName := getKubeHPAMetricName(clientset, service, opts, "spec_target_metric")
+		metricName, hpaMetricName := getKubeHPAMetricName(clientset, service, opts, "spec_target_metric")
+		cpuMetricName := getKubeCPUMetricName(clientset, service, opts)
 		ksmSvc, found, _ := getKubeStateMetricsService(clientset)
 		appLabel := ""
 
@@ -134,9 +135,10 @@ func QueryPrometheus(
 			appLabel = ksmSvc.ObjectMeta.Labels["app.kubernetes.io/instance"]
 		}
 
-		query = createHPAAbsoluteCPUThresholdQuery(metricName, podSelectionRegex, opts.Name, opts.Namespace, appLabel)
+		query = createHPAAbsoluteCPUThresholdQuery(cpuMetricName, metricName, podSelectionRegex, opts.Name, opts.Namespace, appLabel, hpaMetricName)
 	} else if opts.Metric == "memory_hpa_threshold" {
-		metricName := getKubeHPAMetricName(clientset, service, opts, "spec_target_metric")
+		metricName, hpaMetricName := getKubeHPAMetricName(clientset, service, opts, "spec_target_metric")
+		memMetricName := getKubeMemoryMetricName(clientset, service, opts)
 		ksmSvc, found, _ := getKubeStateMetricsService(clientset)
 		appLabel := ""
 
@@ -144,9 +146,9 @@ func QueryPrometheus(
 			appLabel = ksmSvc.ObjectMeta.Labels["app.kubernetes.io/instance"]
 		}
 
-		query = createHPAAbsoluteMemoryThresholdQuery(metricName, podSelectionRegex, opts.Name, opts.Namespace, appLabel)
+		query = createHPAAbsoluteMemoryThresholdQuery(memMetricName, metricName, podSelectionRegex, opts.Name, opts.Namespace, appLabel, hpaMetricName)
 	} else if opts.Metric == "hpa_replicas" {
-		metricName := getKubeHPAMetricName(clientset, service, opts, "status_current_replicas")
+		metricName, hpaMetricName := getKubeHPAMetricName(clientset, service, opts, "status_current_replicas")
 		ksmSvc, found, _ := getKubeStateMetricsService(clientset)
 		appLabel := ""
 
@@ -154,13 +156,15 @@ func QueryPrometheus(
 			appLabel = ksmSvc.ObjectMeta.Labels["app.kubernetes.io/instance"]
 		}
 
-		query = createHPACurrentReplicasQuery(metricName, opts.Name, opts.Namespace, appLabel)
+		query = createHPACurrentReplicasQuery(metricName, opts.Name, opts.Namespace, appLabel, hpaMetricName)
 	}
 
 	if opts.ShouldSum {
 		query = fmt.Sprintf("sum(%s)", query)
 	}
 
+	fmt.Println("QUERY IS", query)
+
 	queryParams := map[string]string{
 		"query": query,
 		"start": fmt.Sprintf("%d", opts.StartRange),
@@ -276,15 +280,20 @@ func getPodSelectionRegex(kind, name string) (string, error) {
 	return fmt.Sprintf("%s-%s", name, suffix), nil
 }
 
-func createHPAAbsoluteCPUThresholdQuery(metricName, podSelectionRegex, hpaName, namespace, appLabel string) string {
+func createHPAAbsoluteCPUThresholdQuery(cpuMetricName, metricName, podSelectionRegex, hpaName, namespace, appLabel, hpaMetricName string) string {
 	kubeMetricsPodSelector := getKubeMetricsPodSelector(podSelectionRegex, namespace)
 
 	kubeMetricsHPASelector := fmt.Sprintf(
-		`hpa="%s",namespace="%s",metric_name="cpu",metric_target_type="utilization"`,
+		`%s="%s",namespace="%s",metric_name="cpu",metric_target_type="utilization"`,
+		hpaMetricName,
 		hpaName,
 		namespace,
 	)
 
+	if cpuMetricName == "kube_pod_container_resource_requests" {
+		kubeMetricsPodSelector += `,resource="cpu",unit="core"`
+	}
+
 	// the kube-state-metrics queries are less prone to error if the field app_kubernetes_io_instance is matched
 	// as well
 	if appLabel != "" {
@@ -293,8 +302,11 @@ func createHPAAbsoluteCPUThresholdQuery(metricName, podSelectionRegex, hpaName,
 	}
 
 	requestCPU := fmt.Sprintf(
-		`sum by (hpa) (label_replace(kube_pod_container_resource_requests_cpu_cores{%s},"hpa", "%s", "", ""))`,
+		`sum by (%s) (label_replace(%s{%s},"%s", "%s", "", ""))`,
+		hpaMetricName,
+		cpuMetricName,
 		kubeMetricsPodSelector,
+		hpaMetricName,
 		hpaName,
 	)
 
@@ -304,18 +316,23 @@ func createHPAAbsoluteCPUThresholdQuery(metricName, podSelectionRegex, hpaName,
 		kubeMetricsHPASelector,
 	)
 
-	return fmt.Sprintf(`%s * on(hpa) %s`, requestCPU, targetCPUUtilThreshold)
+	return fmt.Sprintf(`%s * on(%s) %s`, requestCPU, hpaMetricName, targetCPUUtilThreshold)
 }
 
-func createHPAAbsoluteMemoryThresholdQuery(metricName, podSelectionRegex, hpaName, namespace, appLabel string) string {
+func createHPAAbsoluteMemoryThresholdQuery(memMetricName, metricName, podSelectionRegex, hpaName, namespace, appLabel, hpaMetricName string) string {
 	kubeMetricsPodSelector := getKubeMetricsPodSelector(podSelectionRegex, namespace)
 
 	kubeMetricsHPASelector := fmt.Sprintf(
-		`hpa="%s",namespace="%s",metric_name="memory",metric_target_type="utilization"`,
+		`%s="%s",namespace="%s",metric_name="memory",metric_target_type="utilization"`,
+		hpaMetricName,
 		hpaName,
 		namespace,
 	)
 
+	if memMetricName == "kube_pod_container_resource_requests" {
+		kubeMetricsPodSelector += `,resource="memory",unit="byte"`
+	}
+
 	// the kube-state-metrics queries are less prone to error if the field app_kubernetes_io_instance is matched
 	// as well
 	if appLabel != "" {
@@ -324,8 +341,11 @@ func createHPAAbsoluteMemoryThresholdQuery(metricName, podSelectionRegex, hpaNam
 	}
 
 	requestMem := fmt.Sprintf(
-		`sum by (hpa) (label_replace(kube_pod_container_resource_requests_memory_bytes{%s},"hpa", "%s", "", ""))`,
+		`sum by (%s) (label_replace(%s{%s},"%s", "%s", "", ""))`,
+		hpaMetricName,
+		memMetricName,
 		kubeMetricsPodSelector,
+		hpaMetricName,
 		hpaName,
 	)
 
@@ -335,7 +355,7 @@ func createHPAAbsoluteMemoryThresholdQuery(metricName, podSelectionRegex, hpaNam
 		kubeMetricsHPASelector,
 	)
 
-	return fmt.Sprintf(`%s * on(hpa) %s`, requestMem, targetMemUtilThreshold)
+	return fmt.Sprintf(`%s * on(%s) %s`, requestMem, hpaMetricName, targetMemUtilThreshold)
 }
 
 func getKubeMetricsPodSelector(podSelectionRegex, namespace string) string {
@@ -346,9 +366,10 @@ func getKubeMetricsPodSelector(podSelectionRegex, namespace string) string {
 	)
 }
 
-func createHPACurrentReplicasQuery(metricName, hpaName, namespace, appLabel string) string {
+func createHPACurrentReplicasQuery(metricName, hpaName, namespace, appLabel, hpaMetricName string) string {
 	kubeMetricsHPASelector := fmt.Sprintf(
-		`hpa="%s",namespace="%s"`,
+		`%s="%s",namespace="%s"`,
+		hpaMetricName,
 		hpaName,
 		namespace,
 	)
@@ -372,7 +393,7 @@ type promRawValuesQuery struct {
 }
 
 // getKubeHPAMetricName performs a "best guess" for the name of the kube HPA metric,
-// which was renamed to kube_horizontal_pod_autoscaler... in later versions of kube-state-metrics.
+// which was renamed to kube_horizontalpodautoscaler... in later versions of kube-state-metrics.
 // we query Prometheus for a list of metric names to see if any match the new query
 // value, otherwise we return the deprecated name.
 func getKubeHPAMetricName(
@@ -380,9 +401,81 @@ func getKubeHPAMetricName(
 	service *v1.Service,
 	opts *QueryOpts,
 	suffix string,
+) (string, string) {
+	queryParams := map[string]string{
+		"match[]": fmt.Sprintf("kube_horizontalpodautoscaler_%s", suffix),
+		"start":   fmt.Sprintf("%d", opts.StartRange),
+		"end":     fmt.Sprintf("%d", opts.EndRange),
+	}
+
+	resp := clientset.CoreV1().Services(service.Namespace).ProxyGet(
+		"http",
+		service.Name,
+		fmt.Sprintf("%d", service.Spec.Ports[0].Port),
+		"/api/v1/label/__name__/values",
+		queryParams,
+	)
+
+	rawQuery, err := resp.DoRaw(context.TODO())
+
+	if err != nil {
+		return fmt.Sprintf("kube_hpa_%s", suffix), "hpa"
+	}
+
+	rawQueryObj := &promRawValuesQuery{}
+
+	json.Unmarshal(rawQuery, rawQueryObj)
+
+	if rawQueryObj.Status == "success" && len(rawQueryObj.Data) == 1 {
+		return fmt.Sprintf("kube_horizontalpodautoscaler_%s", suffix), "horizontalpodautoscaler"
+	}
+
+	return fmt.Sprintf("kube_hpa_%s", suffix), "hpa"
+}
+
+func getKubeCPUMetricName(
+	clientset kubernetes.Interface,
+	service *v1.Service,
+	opts *QueryOpts,
+) string {
+	queryParams := map[string]string{
+		"match[]": "kube_pod_container_resource_requests",
+		"start":   fmt.Sprintf("%d", opts.StartRange),
+		"end":     fmt.Sprintf("%d", opts.EndRange),
+	}
+
+	resp := clientset.CoreV1().Services(service.Namespace).ProxyGet(
+		"http",
+		service.Name,
+		fmt.Sprintf("%d", service.Spec.Ports[0].Port),
+		"/api/v1/label/__name__/values",
+		queryParams,
+	)
+
+	rawQuery, err := resp.DoRaw(context.TODO())
+
+	if err != nil {
+		return "kube_pod_container_resource_requests_cpu_cores"
+	}
+
+	rawQueryObj := &promRawValuesQuery{}
+
+	json.Unmarshal(rawQuery, rawQueryObj)
+
+	if rawQueryObj.Status == "success" && len(rawQueryObj.Data) == 1 {
+		return "kube_pod_container_resource_requests"
+	}
+
+	return "kube_pod_container_resource_requests_cpu_cores"
+}
+
+func getKubeMemoryMetricName(
+	clientset kubernetes.Interface,
+	service *v1.Service,
+	opts *QueryOpts,
 ) string {
 	queryParams := map[string]string{
-		"match[]": fmt.Sprintf("kube_horizontal_pod_autoscaler_%s", suffix),
+		"match[]": "kube_pod_container_resource_requests",
 		"start":   fmt.Sprintf("%d", opts.StartRange),
 		"end":     fmt.Sprintf("%d", opts.EndRange),
 	}
@@ -398,7 +491,7 @@ func getKubeHPAMetricName(
 	rawQuery, err := resp.DoRaw(context.TODO())
 
 	if err != nil {
-		return fmt.Sprintf("kube_hpa_%s", suffix)
+		return "kube_pod_container_resource_requests_memory_bytes"
 	}
 
 	rawQueryObj := &promRawValuesQuery{}
@@ -406,8 +499,8 @@ func getKubeHPAMetricName(
 	json.Unmarshal(rawQuery, rawQueryObj)
 
 	if rawQueryObj.Status == "success" && len(rawQueryObj.Data) == 1 {
-		return fmt.Sprintf("kube_horizontal_pod_autoscaler_%s", suffix)
+		return "kube_pod_container_resource_requests"
 	}
 
-	return fmt.Sprintf("kube_hpa_%s", suffix)
+	return "kube_pod_container_resource_requests_memory_bytes"
 }