mirror of
https://github.com/outbackdingo/kubernetes.git
synced 2026-01-27 10:19:35 +00:00
Added unit tests
This commit is contained in:
@@ -4701,3 +4701,401 @@ func TestValidateAllowPodLifecycleSleepActionZeroValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasAPIReferences(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *api.Pod
|
||||
expectRejection bool
|
||||
resource string
|
||||
}{
|
||||
{
|
||||
name: "Empty ServiceAccount in Static Pod",
|
||||
pod: &api.Pod{Spec: api.PodSpec{}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty ServiceAccount",
|
||||
pod: &api.Pod{Spec: api.PodSpec{ServiceAccountName: "default"}},
|
||||
expectRejection: true,
|
||||
resource: "serviceaccounts",
|
||||
},
|
||||
{
|
||||
name: "Empty Volume list",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: nil}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with HostPath volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-hostpath", VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with EmptyDir volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-emptydir", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Secret volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-secret", VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "secrets (via secret volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with ConfigMap volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-configmap", VolumeSource: api.VolumeSource{ConfigMap: &api.ConfigMapVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps (via configmap volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with GCEPersistentDisk volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-gce", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with AWSElasticBlockStore volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-aws", VolumeSource: api.VolumeSource{AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with GitRepo volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-gitrepo", VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with NFS volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-nfs", VolumeSource: api.VolumeSource{NFS: &api.NFSVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with ISCSI volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-iscsi", VolumeSource: api.VolumeSource{ISCSI: &api.ISCSIVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Glusterfs volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-glusterfs", VolumeSource: api.VolumeSource{Glusterfs: &api.GlusterfsVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "endpoints (via glusterFS volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with PersistentVolumeClaim",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-pvc", VolumeSource: api.VolumeSource{PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "persistentvolumeclaims",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with RBD volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-rbd", VolumeSource: api.VolumeSource{RBD: &api.RBDVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with FlexVolume volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-flexvolume", VolumeSource: api.VolumeSource{FlexVolume: &api.FlexVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Cinder volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-cinder", VolumeSource: api.VolumeSource{Cinder: &api.CinderVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with CephFS volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-cephfs", VolumeSource: api.VolumeSource{CephFS: &api.CephFSVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Flocker volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-flocker", VolumeSource: api.VolumeSource{Flocker: &api.FlockerVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with DownwardAPI volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-downwardapi", VolumeSource: api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with FC volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-fc", VolumeSource: api.VolumeSource{FC: &api.FCVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with AzureFile volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-azurefile", VolumeSource: api.VolumeSource{AzureFile: &api.AzureFileVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "secrets (via azureFile volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with VsphereVolume volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-vsphere", VolumeSource: api.VolumeSource{VsphereVolume: &api.VsphereVirtualDiskVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Quobyte volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-quobyte", VolumeSource: api.VolumeSource{Quobyte: &api.QuobyteVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with AzureDisk volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-azuredisk", VolumeSource: api.VolumeSource{AzureDisk: &api.AzureDiskVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with PhotonPersistentDisk volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-photon", VolumeSource: api.VolumeSource{PhotonPersistentDisk: &api.PhotonPersistentDiskVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Projected volume with clustertrustbundles",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{ClusterTrustBundle: &api.ClusterTrustBundleProjection{}}}}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "clustertrustbundles",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Projected volume with secrets",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{Secret: &api.SecretProjection{}}}}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "secrets (via projected volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Projected volume with configmap",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{ConfigMap: &api.ConfigMapProjection{}}}}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps (via projected volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Projected volume with serviceaccounttoken",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{ServiceAccountToken: &api.ServiceAccountTokenProjection{}}}}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "serviceaccounts (via projected volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Projected volume with downwardapi",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{DownwardAPI: &api.DownwardAPIProjection{}}}}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Portworx volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-portworx", VolumeSource: api.VolumeSource{PortworxVolume: &api.PortworxVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with ScaleIO volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-scaleio", VolumeSource: api.VolumeSource{ScaleIO: &api.ScaleIOVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with StorageOS volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-storageos", VolumeSource: api.VolumeSource{StorageOS: &api.StorageOSVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with CSI volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-csi", VolumeSource: api.VolumeSource{CSI: &api.CSIVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "csidrivers (via CSI volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Ephemeral volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-ephemeral", VolumeSource: api.VolumeSource{Ephemeral: &api.EphemeralVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "persistentvolumeclaims (via ephemeral volumes)",
|
||||
},
|
||||
{
|
||||
name: "Non empty volume list with Image volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-image", VolumeSource: api.VolumeSource{Image: &api.ImageVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "No envs",
|
||||
pod: &api.Pod{Spec: api.PodSpec{}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty Env with value",
|
||||
pod: &api.Pod{Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
Env: []api.EnvVar{
|
||||
{
|
||||
Name: "test-env",
|
||||
Value: "TEST_ENV_VAL",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
expectRejection: false,
|
||||
},
|
||||
{
|
||||
name: "Non empty EnvFrom with ConfigMap",
|
||||
pod: &api.Pod{Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
EnvFrom: []api.EnvFromSource{
|
||||
{ConfigMapRef: &api.ConfigMapEnvSource{LocalObjectReference: api.LocalObjectReference{Name: "test"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps",
|
||||
},
|
||||
{
|
||||
name: "Non empty EnvFrom with Secret",
|
||||
pod: &api.Pod{Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
EnvFrom: []api.EnvFromSource{
|
||||
{SecretRef: &api.SecretEnvSource{LocalObjectReference: api.LocalObjectReference{Name: "test"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
expectRejection: true,
|
||||
resource: "secrets",
|
||||
},
|
||||
{
|
||||
name: "Non empty Env with ConfigMap",
|
||||
pod: &api.Pod{Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
Env: []api.EnvVar{
|
||||
{
|
||||
Name: "test-env",
|
||||
ValueFrom: &api.EnvVarSource{ConfigMapKeyRef: &api.ConfigMapKeySelector{LocalObjectReference: api.LocalObjectReference{Name: "test"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps",
|
||||
},
|
||||
{
|
||||
name: "Non empty Env with Secret",
|
||||
pod: &api.Pod{Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
Env: []api.EnvVar{
|
||||
{
|
||||
Name: "test-env",
|
||||
ValueFrom: &api.EnvVarSource{SecretKeyRef: &api.SecretKeySelector{LocalObjectReference: api.LocalObjectReference{Name: "test"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
expectRejection: true,
|
||||
resource: "secrets",
|
||||
},
|
||||
{
|
||||
name: "Multiple volume list where invalid volume comes after valid volume source",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-portworx", VolumeSource: api.VolumeSource{PortworxVolume: &api.PortworxVolumeSource{}}},
|
||||
{Name: "test-volume-configmap", VolumeSource: api.VolumeSource{ConfigMap: &api.ConfigMapVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps (via configmap volumes)",
|
||||
},
|
||||
{
|
||||
name: "Multiple volume list where invalid configmap volume comes after valid downwardapi projected volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{DownwardAPI: &api.DownwardAPIProjection{}}}}}},
|
||||
{Name: "test-volume-configmap", VolumeSource: api.VolumeSource{ConfigMap: &api.ConfigMapVolumeSource{}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps (via configmap volumes)",
|
||||
},
|
||||
{
|
||||
name: "Multiple volume list where invalid configmap projected volume comes after valid downwardapi projected volume",
|
||||
pod: &api.Pod{Spec: api.PodSpec{Volumes: []api.Volume{
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{DownwardAPI: &api.DownwardAPIProjection{}}}}}},
|
||||
{Name: "test-volume-projected", VolumeSource: api.VolumeSource{Projected: &api.ProjectedVolumeSource{Sources: []api.VolumeProjection{{ConfigMap: &api.ConfigMapProjection{}}}}}},
|
||||
}}},
|
||||
expectRejection: true,
|
||||
resource: "configmaps (via projected volumes)",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actualResult, resource, _ := HasAPIObjectReference(test.pod)
|
||||
if test.expectRejection != actualResult || resource != test.resource {
|
||||
t.Errorf("unexpected result, expected %v but got %v, expected resource %v, but got %v", test.expectRejection, actualResult, test.resource, resource)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -175,8 +176,8 @@ func TestDecodeSinglePodRejectsClusterTrustBundleVolumes(t *testing.T) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
_, _, err = tryDecodeSinglePod(json, noDefault)
|
||||
if !errors.Is(err, ErrStaticPodTriedToUseClusterTrustBundle) {
|
||||
t.Errorf("Got error %q, want %q", err, ErrStaticPodTriedToUseClusterTrustBundle)
|
||||
if !strings.Contains(err.Error(), "may not reference clustertrustbundles") {
|
||||
t.Errorf("Got error %q, want %q", err, fmt.Errorf("static pods may not reference clustertrustbundles API objects"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,8 +232,8 @@ func TestDecodeSinglePodRejectsResourceClaims(t *testing.T) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
_, _, err = tryDecodeSinglePod(json, noDefault)
|
||||
if !errors.Is(err, ErrStaticPodTriedToUseResourceClaims) {
|
||||
t.Errorf("Got error %q, want %q", err, ErrStaticPodTriedToUseResourceClaims)
|
||||
if !strings.Contains(err.Error(), "may not reference resourceclaims") {
|
||||
t.Errorf("Got error %q, want %q", err, fmt.Errorf("static pods may not reference resourceclaims API objects"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1032,7 +1032,7 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
||||
name: "forbid create of pod referencing service account",
|
||||
podsGetter: noExistingPods,
|
||||
attributes: admission.NewAttributesRecord(sapod, nil, podKind, sapod.Namespace, sapod.Name, podResource, "", admission.Create, &metav1.CreateOptions{}, false, mynode),
|
||||
err: "reference a service account",
|
||||
err: "can not create pods that reference serviceaccounts",
|
||||
},
|
||||
{
|
||||
name: "forbid create of pod referencing secret",
|
||||
@@ -1056,7 +1056,7 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
||||
name: "forbid create of pod referencing persistentvolumeclaim",
|
||||
podsGetter: noExistingPods,
|
||||
attributes: admission.NewAttributesRecord(pvcpod, nil, podKind, pvcpod.Namespace, pvcpod.Name, podResource, "", admission.Create, &metav1.CreateOptions{}, false, mynode),
|
||||
err: "reference persistentvolumeclaims",
|
||||
err: "can not create pods that reference persistentvolumeclaims",
|
||||
},
|
||||
{
|
||||
name: "forbid create of pod referencing resourceclaim",
|
||||
|
||||
Reference in New Issue
Block a user