diff --git a/support/authentication.go b/support/authentication.go new file mode 100644 index 0000000..89794de --- /dev/null +++ b/support/authentication.go @@ -0,0 +1,40 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package support + +import ( + "github.com/onsi/gomega" + + authenticationv1 "k8s.io/api/authentication/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func CreateToken(t Test, namespace string, serviceAccount *corev1.ServiceAccount) string { + t.T().Helper() + + treq := &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + ExpirationSeconds: Ptr(int64(3600)), + }, + } + treq, err := t.Client().Core().CoreV1().ServiceAccounts(namespace).CreateToken(t.Ctx(), serviceAccount.Name, treq, metav1.CreateOptions{}) + t.Expect(err).NotTo(gomega.HaveOccurred()) + t.T().Logf("Created TokenRequest %s/%s successfully", treq.Namespace, treq.Name) + + return treq.Status.Token +} diff --git a/support/config.go b/support/config.go new file mode 100644 index 0000000..48d322c --- /dev/null +++ b/support/config.go @@ -0,0 +1,56 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package support + +import ( + "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ingressConfigResource = schema.GroupVersionResource{Group: "config.openshift.io", Version: "v1", Resource: "ingresses"} +var infrastructureConfigResource = schema.GroupVersionResource{Group: "config.openshift.io", Version: "v1", Resource: "infrastructures"} + +func GetOpenShiftIngressDomain(test Test) string { + test.T().Helper() + + cluster, err := test.Client().Dynamic().Resource(ingressConfigResource).Get(test.Ctx(), "cluster", metav1.GetOptions{}) + test.Expect(err).NotTo(gomega.HaveOccurred()) + + ingressDomain, found, err := unstructured.NestedString(cluster.UnstructuredContent(), "spec", "domain") + test.Expect(err).NotTo(gomega.HaveOccurred()) + test.Expect(found).To(gomega.BeTrue()) + + test.T().Logf("Ingress domain: %s", ingressDomain) + return ingressDomain +} + +func GetOpenShiftApiUrl(test Test) string { + test.T().Helper() + + cluster, err := test.Client().Dynamic().Resource(infrastructureConfigResource).Get(test.Ctx(), "cluster", metav1.GetOptions{}) + test.Expect(err).NotTo(gomega.HaveOccurred()) + + openShiftApiUrl, found, err := unstructured.NestedString(cluster.UnstructuredContent(), "status", "apiServerURL") + test.Expect(err).NotTo(gomega.HaveOccurred()) + test.Expect(found).To(gomega.BeTrue()) + + test.T().Logf("OpenShift API URL: %s", openShiftApiUrl) + return openShiftApiUrl +} diff --git a/support/core.go b/support/core.go index 70c48c2..54f25e2 100644 --- a/support/core.go +++ b/support/core.go @@ -23,11 +23,14 @@ import ( "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) func CreateConfigMap(t Test, namespace string, content map[string][]byte) *corev1.ConfigMap { + t.T().Helper() + configMap := &corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{ APIVersion: corev1.SchemeGroupVersion.String(), @@ -98,7 +101,10 @@ func storeContainerLog(t Test, namespace *corev1.Namespace, podName, containerNa options := corev1.PodLogOptions{Container: containerName} stream, err := t.Client().Core().CoreV1().Pods(namespace.Name).GetLogs(podName, &options).Stream(t.Ctx()) - t.Expect(err).NotTo(gomega.HaveOccurred()) + if err != nil { + t.T().Logf("Failed to retrieve logs for Pod Container %s/%s/%s, logs cannot be stored", namespace.Name, podName, containerName) + return + } defer func() { t.Expect(stream.Close()).To(gomega.Succeed()) @@ -110,3 +116,51 @@ func storeContainerLog(t Test, namespace *corev1.Namespace, podName, containerNa containerLogFileName := "pod-" + podName + "-" + containerName WriteToOutputDir(t, containerLogFileName, Log, bytes) } + +func CreateServiceAccount(t Test, namespace string) *corev1.ServiceAccount { + t.T().Helper() + + serviceAccount := &corev1.ServiceAccount{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ServiceAccount", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "sa-", + Namespace: namespace, + }, + } + serviceAccount, err := t.Client().Core().CoreV1().ServiceAccounts(namespace).Create(t.Ctx(), serviceAccount, metav1.CreateOptions{}) + t.Expect(err).NotTo(gomega.HaveOccurred()) + t.T().Logf("Created ServiceAccount %s/%s successfully", serviceAccount.Namespace, serviceAccount.Name) + + return serviceAccount +} + +func CreatePersistentVolumeClaim(t Test, namespace string, storageSize string, accessMode ...corev1.PersistentVolumeAccessMode) *corev1.PersistentVolumeClaim { + t.T().Helper() + + pvc := &corev1.PersistentVolumeClaim{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "PersistentVolumeClaim", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "pvc-", + Namespace: namespace, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: accessMode, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse(storageSize), + }, + }, + }, + } + pvc, err := t.Client().Core().CoreV1().PersistentVolumeClaims(namespace).Create(t.Ctx(), pvc, metav1.CreateOptions{}) + t.Expect(err).NotTo(gomega.HaveOccurred()) + t.T().Logf("Created PersistentVolumeClaim %s/%s successfully", pvc.Namespace, pvc.Name) + + return pvc +} diff --git a/support/image.go b/support/image.go new file mode 100644 index 0000000..d03b60e --- /dev/null +++ b/support/image.go @@ -0,0 +1,34 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package support + +import ( + "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + imagev1 "github.com/openshift/api/image/v1" +) + +func GetImageStream(t Test, namespace string, name string) *imagev1.ImageStream { + t.T().Helper() + + is, err := t.Client().Image().ImageV1().ImageStreams(namespace).Get(t.Ctx(), name, metav1.GetOptions{}) + t.Expect(err).NotTo(gomega.HaveOccurred()) + + return is +} diff --git a/support/rbac.go b/support/rbac.go new file mode 100644 index 0000000..0963329 --- /dev/null +++ b/support/rbac.go @@ -0,0 +1,78 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package support + +import ( + "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func CreateRole(t Test, namespace string, policyRules []rbacv1.PolicyRule) *rbacv1.Role { + t.T().Helper() + + role := &rbacv1.Role{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "Role", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "role-", + Namespace: namespace, + }, + Rules: policyRules, + } + role, err := t.Client().Core().RbacV1().Roles(namespace).Create(t.Ctx(), role, metav1.CreateOptions{}) + t.Expect(err).NotTo(gomega.HaveOccurred()) + t.T().Logf("Created Role %s/%s successfully", role.Namespace, role.Name) + + return role +} + +func CreateRoleBinding(t Test, namespace string, serviceAccount *corev1.ServiceAccount, role *rbacv1.Role) *rbacv1.RoleBinding { + t.T().Helper() + + roleBinding := &rbacv1.RoleBinding{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "RoleBinding", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "rb-", + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.SchemeGroupVersion.Group, + Kind: "Role", + Name: role.Name, + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: corev1.SchemeGroupVersion.Group, + Name: serviceAccount.Name, + Namespace: serviceAccount.Namespace, + }, + }, + } + rb, err := t.Client().Core().RbacV1().RoleBindings(namespace).Create(t.Ctx(), roleBinding, metav1.CreateOptions{}) + t.Expect(err).NotTo(gomega.HaveOccurred()) + t.T().Logf("Created RoleBinding %s/%s successfully", role.Namespace, role.Name) + + return rb +}