diff --git a/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client.go b/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client.go index cc0676d5c431..c3a030b24baa 100644 --- a/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client.go +++ b/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client.go @@ -55,6 +55,10 @@ const ( // permissions error ErrorCodePermissions = "PERMISSIONS_ERROR" + // ErrorCodeVmExternalIpAccessPolicyConstraint is an error code in InstanceErrorInfo if the user + // is facing errors caused by vmExternalIpAccess policy constraint misconfiguration. + ErrorCodeVmExternalIpAccessPolicyConstraint = "VM_EXTERNAL_IP_ACCESS_POLICY_CONSTRAINT" + // ErrorCodeOther is an error code used in InstanceErrorInfo if other error occurs. ErrorCodeOther = "OTHER" ) @@ -306,6 +310,9 @@ func (client *autoscalingGceClientV1) FetchMigInstances(migRef GceRef) ([]cloudp } else if isPermissionsError(instanceError.Code) { errorInfo.ErrorClass = cloudprovider.OtherErrorClass errorInfo.ErrorCode = ErrorCodePermissions + } else if isVmExternalIpAccessPolicyConstraintError(instanceError) { + errorInfo.ErrorClass = cloudprovider.OtherErrorClass + errorInfo.ErrorCode = ErrorCodeVmExternalIpAccessPolicyConstraint } else if isInstanceNotRunningYet(gceInstance) { if !errorFound { // do not override error code with OTHER @@ -369,6 +376,11 @@ func isPermissionsError(errorCode string) bool { return strings.Contains(errorCode, "PERMISSIONS_ERROR") } +func isVmExternalIpAccessPolicyConstraintError(err *gce.ManagedInstanceLastAttemptErrorsErrors) bool { + regexProjectPolicyConstraint := regexp.MustCompile(`Constraint constraints/compute.vmExternalIpAccess violated for project`) + return strings.Contains(err.Code, "CONDITION_NOT_MET") && regexProjectPolicyConstraint.MatchString(err.Message) +} + func isInstanceNotRunningYet(gceInstance *gce.ManagedInstance) bool { return gceInstance.InstanceStatus == "" || gceInstance.InstanceStatus == "PROVISIONING" || gceInstance.InstanceStatus == "STAGING" } diff --git a/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client_test.go b/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client_test.go index d270a7f41202..9321ab167bf5 100644 --- a/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client_test.go +++ b/cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client_test.go @@ -143,6 +143,7 @@ func TestErrors(t *testing.T) { testCases := []struct { errorCodes []string + errorMessage string expectedErrorCode string expectedErrorClass cloudprovider.InstanceErrorClass }{ @@ -166,6 +167,12 @@ func TestErrors(t *testing.T) { expectedErrorCode: "PERMISSIONS_ERROR", expectedErrorClass: cloudprovider.OtherErrorClass, }, + { + errorCodes: []string{"CONDITION_NOT_MET"}, + errorMessage: "Instance 'myinst' creation failed: Constraint constraints/compute.vmExternalIpAccess violated for project 1234567890.", + expectedErrorCode: "VM_EXTERNAL_IP_ACCESS_POLICY_CONSTRAINT", + expectedErrorClass: cloudprovider.OtherErrorClass, + }, { errorCodes: []string{"xyz", "abc"}, expectedErrorCode: "OTHER", @@ -183,7 +190,8 @@ func TestErrors(t *testing.T) { Errors: &gce_api.ManagedInstanceLastAttemptErrors{ Errors: []*gce_api.ManagedInstanceLastAttemptErrorsErrors{ { - Code: errorCode, + Code: errorCode, + Message: tc.errorMessage, }, }, },