diff --git a/.github/workflows/jobs.yaml b/.github/workflows/jobs.yaml index 4f5e9c5ba..2752242d4 100644 --- a/.github/workflows/jobs.yaml +++ b/.github/workflows/jobs.yaml @@ -1539,7 +1539,7 @@ jobs: go tool cover -func=all.out | grep total > tmp2 result=`cat tmp2 | awk 'END {print $3}'` result=${result%\%} - threshold=66.1 + threshold=67.2 echo "Result:" echo "$result%" if (( $(echo "$result >= $threshold" |bc -l) )); then diff --git a/operatorapi/tenants.go b/operatorapi/tenants.go index daa233829..626b119ed 100644 --- a/operatorapi/tenants.go +++ b/operatorapi/tenants.go @@ -2588,14 +2588,11 @@ func getTenantUpdatePoolResponse(session *models.Principal, params operator_api. client: opClientClientSet, } - t, err := updateTenantPools(ctx, opClient, params.Namespace, params.Tenant, params.Body.Pools) + tenant, err := updateTenantPools(ctx, opClient, params.Namespace, params.Tenant, params.Body.Pools) if err != nil { restapi.LogError("error updating Tenant's pools: %v", err) return nil, restapi.ErrorWithContext(ctx, err) } - - // parse it to models.Tenant - tenant := getTenantInfo(t) return tenant, nil } @@ -2608,7 +2605,7 @@ func updateTenantPools( namespace string, tenantName string, poolsReq []*models.Pool, -) (*miniov2.Tenant, error) { +) (*models.Tenant, error) { minInst, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{}) if err != nil { return nil, err @@ -2638,7 +2635,7 @@ func updateTenantPools( if err != nil { return nil, err } - return tenantUpdated, nil + return getTenantInfo(tenantUpdated), nil } func getTenantYAML(session *models.Principal, params operator_api.GetTenantYAMLParams) (*models.TenantYAML, *models.Error) { diff --git a/operatorapi/tenants_2_test.go b/operatorapi/tenants_2_test.go index 82080b8c2..d628d3d66 100644 --- a/operatorapi/tenants_2_test.go +++ b/operatorapi/tenants_2_test.go @@ -39,6 +39,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" ) type TenantTestSuite struct { @@ -1204,6 +1205,203 @@ func (suite *TenantTestSuite) initTenantUpdatePoolsRequest() (params operator_ap return params, api } +func (suite *TenantTestSuite) TestUpdateTenantPoolsWithPoolError() { + opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) { + return &miniov2.Tenant{}, nil + } + _, err := updateTenantPools(context.Background(), suite.opClient, "mock-namespace", "mock-tenant", []*models.Pool{{}}) + suite.assert.NotNil(err) +} + +func (suite *TenantTestSuite) TestUpdateTenantPoolsWithPatchError() { + size := int64(1024) + seconds := int64(5) + weight := int32(1024) + servers := int64(4) + volumes := int32(4) + mockString := "mock-string" + pools := []*models.Pool{{ + VolumeConfiguration: &models.PoolVolumeConfiguration{ + Size: &size, + }, + Servers: &servers, + VolumesPerServer: &volumes, + Resources: &models.PoolResources{ + Requests: map[string]int64{ + "cpu": 1, + }, + Limits: map[string]int64{ + "memory": 1, + }, + }, + Tolerations: models.PoolTolerations{{ + TolerationSeconds: &models.PoolTolerationSeconds{ + Seconds: &seconds, + }, + }}, + Affinity: &models.PoolAffinity{ + NodeAffinity: &models.PoolAffinityNodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &models.PoolAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution{ + NodeSelectorTerms: []*models.NodeSelectorTerm{{ + MatchExpressions: []*models.NodeSelectorTermMatchExpressionsItems0{{ + Key: &mockString, + Operator: &mockString, + }}, + }}, + }, + PreferredDuringSchedulingIgnoredDuringExecution: []*models.PoolAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{{ + Weight: &weight, + Preference: &models.NodeSelectorTerm{ + MatchFields: []*models.NodeSelectorTermMatchFieldsItems0{{ + Key: &mockString, + Operator: &mockString, + }}, + }, + }}, + }, + PodAffinity: &models.PoolAffinityPodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []*models.PodAffinityTerm{{ + LabelSelector: &models.PodAffinityTermLabelSelector{ + MatchExpressions: []*models.PodAffinityTermLabelSelectorMatchExpressionsItems0{{ + Key: &mockString, + Operator: &mockString, + }}, + }, + TopologyKey: &mockString, + }}, + PreferredDuringSchedulingIgnoredDuringExecution: []*models.PoolAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{{ + PodAffinityTerm: &models.PodAffinityTerm{ + LabelSelector: &models.PodAffinityTermLabelSelector{ + MatchExpressions: []*models.PodAffinityTermLabelSelectorMatchExpressionsItems0{{ + Key: &mockString, + Operator: &mockString, + }}, + }, + TopologyKey: &mockString, + }, + Weight: &weight, + }}, + }, + PodAntiAffinity: &models.PoolAffinityPodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []*models.PodAffinityTerm{{ + LabelSelector: &models.PodAffinityTermLabelSelector{ + MatchExpressions: []*models.PodAffinityTermLabelSelectorMatchExpressionsItems0{{ + Key: &mockString, + Operator: &mockString, + }}, + }, + TopologyKey: &mockString, + }}, + PreferredDuringSchedulingIgnoredDuringExecution: []*models.PoolAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{{ + PodAffinityTerm: &models.PodAffinityTerm{ + LabelSelector: &models.PodAffinityTermLabelSelector{ + MatchExpressions: []*models.PodAffinityTermLabelSelectorMatchExpressionsItems0{{ + Key: &mockString, + Operator: &mockString, + }}, + }, + TopologyKey: &mockString, + }, + Weight: &weight, + }}, + }, + }, + }} + opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) { + return &miniov2.Tenant{}, nil + } + opClientTenantPatchMock = func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*miniov2.Tenant, error) { + return nil, errors.New("mock-patch-error") + } + _, err := updateTenantPools(context.Background(), suite.opClient, "mock-namespace", "mock-tenant", pools) + suite.assert.NotNil(err) +} + +func (suite *TenantTestSuite) TestUpdateTenantPoolsWithoutError() { + fscp := corev1.PodFSGroupChangePolicy("OnRootMismatch") + seconds := int64(10) + opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) { + return &miniov2.Tenant{}, nil + } + opClientTenantPatchMock = func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*miniov2.Tenant, error) { + return &miniov2.Tenant{ + Spec: miniov2.TenantSpec{ + Pools: []miniov2.Pool{{ + VolumeClaimTemplate: &corev1.PersistentVolumeClaim{ + Spec: corev1.PersistentVolumeClaimSpec{ + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), + }, + }, + }, + }, + SecurityContext: &corev1.PodSecurityContext{ + RunAsUser: &[]int64{1000}[0], + RunAsGroup: &[]int64{1000}[0], + FSGroup: &[]int64{1000}[0], + FSGroupChangePolicy: &fscp, + }, + Tolerations: []corev1.Toleration{{ + TolerationSeconds: &seconds, + }}, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceLimitsMemory: resource.MustParse("1"), + }, + }, + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchExpressions: []corev1.NodeSelectorRequirement{{}}, + }}, + }, + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.PreferredSchedulingTerm{{ + Preference: corev1.NodeSelectorTerm{}, + }}, + }, + PodAffinity: &corev1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{}}, + }, + }}, + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{{ + PodAffinityTerm: corev1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{}}, + }, + }, + }}, + }, + PodAntiAffinity: &corev1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{}}, + }, + }}, + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{{ + PodAffinityTerm: corev1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{}}, + }, + }, + }}, + }, + }, + }}, + }, + }, nil + } + _, err := updateTenantPools(context.Background(), suite.opClient, "mock-namespace", "mock-tenant", []*models.Pool{}) + suite.assert.Nil(err) +} + func (suite *TenantTestSuite) TestTenantUpdateCertificateHandlerWithError() { params, api := suite.initTenantUpdateCertificateRequest() response := api.OperatorAPITenantUpdateCertificateHandler.Handle(params, &models.Principal{})