This repository has been archived by the owner on Oct 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WIP] Replace oc commands in OperatorSource automated test with clien…
…t-go Signed-off-by: Pratik Jagrut <[email protected]>
- Loading branch information
Pratik Jagrut
committed
May 18, 2019
1 parent
fdeb4b9
commit 497604f
Showing
2 changed files
with
164 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,146 +1,93 @@ | ||
package operatorsource | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"github.com/stretchr/testify/require" | ||
corev1 "k8s.io/api/core/v1" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
const ShellToUse = "bash" | ||
|
||
func Shellout(command string) (string, string, error) { | ||
var stdout bytes.Buffer | ||
var stderr bytes.Buffer | ||
cmd := exec.Command(ShellToUse, "-c", command) | ||
cmd.Stdout = &stdout | ||
cmd.Stderr = &stderr | ||
err := cmd.Run() | ||
return stdout.String(), stderr.String(), err | ||
} | ||
var ( | ||
Client = NewTestClient() | ||
namespace = "openshift-operators" | ||
subName = "devconsole" | ||
subscription, suberr = Client.GetSubscription(subName, namespace) | ||
) | ||
|
||
func Test_OperatorSource_oc_commands(t *testing.T) { | ||
func Test_OperatorSource(t *testing.T) { | ||
|
||
defer CleanUp(t) | ||
|
||
t.Run("login", func(t *testing.T) { Login(t) }) | ||
t.Run("subscription", func(t *testing.T) { Subscription(t) }) | ||
t.Run("install plan", func(t *testing.T) { InstallPlan(t) }) | ||
t.Run("operator pod", func(t *testing.T) { OperatorPod(t) }) | ||
} | ||
|
||
func Login(t *testing.T) { | ||
// Start - Login to oc | ||
out, _, err := Shellout("oc login -u " + os.Getenv("OC_LOGIN_USERNAME") + " -p " + os.Getenv("OC_LOGIN_PASSWORD")) | ||
if err != nil { | ||
t.Fatalf("error: %v\n", err) | ||
} else { | ||
require.True(t, strings.Contains(out, "Login successful."), "Expecting successful login") | ||
} | ||
} | ||
|
||
func Subscription(t *testing.T) { | ||
// 1) Verify that the subscription was created | ||
out, errout, err := Shellout("oc get sub devconsole -n openshift-operators") | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Fatalf("error: %v\n", err) | ||
} else { | ||
require.True(t, strings.Contains(out, "devconsole"), "Expecting the subscription name to be found") | ||
require.True(t, strings.Contains(out, "installed-custom-openshift-operators"), "Expecting the subscription namespace to be found") | ||
if suberr != nil { | ||
t.Fatal(suberr) | ||
} | ||
fmt.Printf("Subscription Name: %s\nCatalog Source: %s\n", subscription.Name, subscription.Spec.CatalogSource) | ||
require.Equal(t, subName, subscription.Name) | ||
require.Equal(t, "installed-custom-openshift-operators", subscription.Spec.CatalogSource) | ||
} | ||
|
||
func InstallPlan(t *testing.T) { | ||
// 2) Find the name of the install plan | ||
out, errout, err := Shellout("oc get sub devconsole -n openshift-operators -o jsonpath='{.status.installplan.name}'") | ||
var installPlan string | ||
installPlanName := subscription.Status.Install.Name | ||
fmt.Printf("Install Plan Name: %s\n", installPlanName) | ||
installPlan, err := Client.GetInstallPlan(installPlanName, namespace) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Fatalf("error: %v\n", err) | ||
} else { | ||
installPlan = out | ||
t.Fatal(err) | ||
} | ||
|
||
// 3) Verify the install plan | ||
out, errout, err = Shellout(fmt.Sprintf("oc get installplan %s -n openshift-operators", installPlan)) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Fatalf("error: %v\n", err) | ||
} else { | ||
require.True(t, strings.Contains(out, installPlan), "Expecting the Install Plan name to be found") | ||
require.True(t, strings.Contains(out, "devconsole-operator.v0.1.0"), "Expecting the Operator release to be found") | ||
require.True(t, strings.Contains(out, "Automatic"), "Expecting the approval method to be found") | ||
require.True(t, strings.Contains(out, "true"), "Expecting the approved state to be found") | ||
fmt.Printf("CSV: %v\n", installPlan.Spec.ClusterServiceVersionNames[0]) | ||
fmt.Printf("Install Plan Approval: %v\n", installPlan.Spec.Approval) | ||
fmt.Printf("Install Plan Approved: %v\n", installPlan.Spec.Approved) | ||
|
||
require.Equal(t, "devconsole-operator.v0.1.0", installPlan.Spec.ClusterServiceVersionNames[0]) | ||
require.Equal(t, "Automatic", string(installPlan.Spec.Approval)) | ||
if !installPlan.Spec.Approved { | ||
require.FailNow(t, "Install plan approved is false") | ||
} | ||
} | ||
|
||
func OperatorPod(t *testing.T) { | ||
// Verify that the operator's pod is running | ||
out, errout, err := Shellout("oc get pods -l name=devconsole-operator -n openshift-operators -o jsonpath='{.items[*].status.phase}'") | ||
// 3) Check operator pod status, fail status != Running | ||
label := "name=devconsole-operator" | ||
pod, err := Client.GetPodByLabel(label, namespace) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Fatalf("error: %v\n", err) | ||
} else { | ||
require.True(t, strings.Contains(out, "Running"), "Expecting the state of the Operator pod to be running") | ||
t.Fatal(err) | ||
} | ||
if pod == nil { | ||
t.Fatal("pod returned empty") | ||
} | ||
fmt.Printf("Pod Name: %v\nPod status: %v\n", pod.Name, pod.Status.Phase) | ||
require.Equal(t, pod.Status.Phase, corev1.PodRunning) | ||
} | ||
|
||
func CleanUp(t *testing.T) { | ||
// Clean up resources | ||
operatorSourceName := os.Getenv("OPSRC_NAME") | ||
operatorVersion := os.Getenv("DEVCONSOLE_OPERATOR_VERSION") | ||
|
||
out, errout, err := Shellout(fmt.Sprintf("oc delete opsrc %s -n openshift-marketplace", operatorSourceName)) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Logf("error: %v\n", err) | ||
} else { | ||
t.Logf(out) | ||
} | ||
|
||
out, errout, err = Shellout("oc delete sub devconsole -n openshift-operators") | ||
err := Client.Delete("installplan", subscription.Status.Install.Name, namespace) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Logf("error: %v\n", err) | ||
} else { | ||
t.Logf(out) | ||
t.Logf("Error: %v\n", err) | ||
} | ||
|
||
out, errout, err = Shellout("oc delete catsrc installed-custom-openshift-operators -n openshift-operators") | ||
err = Client.Delete("catsrc", subscription.Spec.CatalogSource, namespace) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Logf("error: %v\n", err) | ||
} else { | ||
t.Logf(out) | ||
t.Logf("Error: %v\n", err) | ||
} | ||
|
||
out, errout, err = Shellout("oc delete csc installed-custom-openshift-operators -n openshift-marketplace") | ||
err = Client.Delete("sub", subName, namespace) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Logf("error: %v\n", err) | ||
} else { | ||
t.Logf(out) | ||
t.Logf("Error: %v\n", err) | ||
} | ||
|
||
out, errout, err = Shellout(fmt.Sprintf("oc delete csv devconsole-operator.v%s -n openshift-operators", operatorVersion)) | ||
csv := fmt.Sprintf("devconsole-operator.v%s", operatorVersion) | ||
err = Client.Delete("csv", csv, namespace) | ||
if err != nil { | ||
t.Logf("stdout: %s\n", out) | ||
t.Logf("stderr: %s\n", errout) | ||
t.Logf("error: %v\n", err) | ||
} else { | ||
t.Logf(out) | ||
t.Logf("Error: %v\n", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package operatorsource | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
apis_v1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" | ||
client "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client" | ||
v1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/typed/operators/v1alpha1" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes" | ||
"k8s.io/client-go/tools/clientcmd" | ||
"log" | ||
"os" | ||
) | ||
|
||
//ClientSetK8sCoreAPI returns new Clientset for the given config, use to interact with K8s resources like pods | ||
func ClientSetK8sCoreAPI(kubeconfig string) *kubernetes.Clientset { | ||
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
clientset, err := kubernetes.NewForConfig(config) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return clientset | ||
} | ||
|
||
//ClientSet Creates clientset for given config, use to interact with custom resources | ||
func ClientSet(kubeconfig string) v1alpha1.OperatorsV1alpha1Interface { | ||
client, err := client.NewClient(kubeconfig) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return client.OperatorsV1alpha1() | ||
} | ||
|
||
// TestClient wraps all the clientsets required while testing | ||
type TestClient struct { | ||
K8sClient *kubernetes.Clientset | ||
OperatorClient v1alpha1.OperatorsV1alpha1Interface | ||
} | ||
|
||
//NewTestClient initialises the TestClient | ||
func NewTestClient() *TestClient { | ||
kubeconfig := os.Getenv("KUBECONFIG") | ||
|
||
return &TestClient{ | ||
K8sClient: ClientSetK8sCoreAPI(kubeconfig), | ||
OperatorClient: ClientSet(kubeconfig), | ||
} | ||
} | ||
|
||
// GetPodByLabel is a function that takes label and namespace and returns the pod and error | ||
func (tc *TestClient) GetPodByLabel(label string, namespace string) (*corev1.Pod, error) { | ||
|
||
pods, err := tc.K8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: label}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(pods.Items) == 0 { | ||
return nil, nil | ||
} | ||
return &pods.Items[0], nil | ||
} | ||
|
||
//GetSubscription returns subscription struct | ||
func (tc *TestClient) GetSubscription(subName, namespace string) (*apis_v1alpha1.Subscription, error) { | ||
subscription, err := tc.OperatorClient.Subscriptions(namespace).Get(subName, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return subscription, nil | ||
} | ||
|
||
//GetInstallPlan returns install plan struct | ||
func (tc *TestClient) GetInstallPlan(installPlanName, namespace string) (*apis_v1alpha1.InstallPlan, error) { | ||
|
||
installPlan, err := tc.OperatorClient.InstallPlans(namespace).Get(installPlanName, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return installPlan, nil | ||
} | ||
|
||
//Delete takes kind, name and namespace of the resource and deletes it. Returns an error if one occurs. | ||
func (tc *TestClient) Delete(resource, name, namespace string) error { | ||
switch resource { | ||
case "subscription", "sub": | ||
err := tc.OperatorClient.Subscriptions(namespace).Delete(name, &metav1.DeleteOptions{}) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
case "installplan": | ||
err := tc.OperatorClient.InstallPlans(namespace).Delete(name, &metav1.DeleteOptions{}) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
case "catalogsource", "catsrc": | ||
err := tc.OperatorClient.CatalogSources(namespace).Delete(name, &metav1.DeleteOptions{}) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
case "clusterserviceversion", "csv": | ||
err := tc.OperatorClient.ClusterServiceVersions(namespace).Delete(name, &metav1.DeleteOptions{}) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
default: | ||
option := fmt.Sprintf("Invalid resource: %s", resource) | ||
return errors.New(option) | ||
|
||
} | ||
} |