Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 0 additions & 163 deletions internal/util/k8sutil/k8sutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,22 @@ package k8sutil

import (
"bytes"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"regexp"
"strings"
"unicode"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)

// GetKubeconfigAndNamespace returns the *rest.Config and default namespace defined in the
Expand Down Expand Up @@ -148,161 +140,6 @@ func TrimDNS1123Label(label string) string {
return label
}

// ForceRunModeEnv indicates if the operator should be forced to run in either local
// or cluster mode (currently only used for local mode)
var ForceRunModeEnv = "OSDK_FORCE_RUN_MODE"

type RunModeType string

const (
LocalRunMode RunModeType = "local"
ClusterRunMode RunModeType = "cluster"
)

var logk8sutil = logf.Log.WithName("k8sutil")

// GetWatchNamespace returns the namespace the operator should be watching for changes
func GetWatchNamespace() (string, error) {
ns, found := os.LookupEnv(WatchNamespaceEnvVar)
if !found {
return "", fmt.Errorf("%s must be set", WatchNamespaceEnvVar)
}
return ns, nil
}

// ErrNoNamespace indicates that a namespace could not be found for the current
// environment
var ErrNoNamespace = fmt.Errorf("namespace not found for current environment")

// ErrRunLocal indicates that the operator is set to run in local mode (this error
// is returned by functions that only work on operators running in cluster mode)
var ErrRunLocal = fmt.Errorf("operator run mode forced to local")

// GetOperatorNamespace returns the namespace the operator should be running in.
func GetOperatorNamespace() (string, error) {
if isRunModeLocal() {
return "", ErrRunLocal
}
nsBytes, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
if os.IsNotExist(err) {
return "", ErrNoNamespace
}
return "", err
}
ns := strings.TrimSpace(string(nsBytes))
logk8sutil.V(1).Info("Found namespace", "Namespace", ns)
return ns, nil
}

// GetOperatorName return the operator name
func GetOperatorName() (string, error) {
operatorName, found := os.LookupEnv(OperatorNameEnvVar)
if !found {
return "", fmt.Errorf("%s must be set", OperatorNameEnvVar)
}
if len(operatorName) == 0 {
return "", fmt.Errorf("%s must not be empty", OperatorNameEnvVar)
}
return operatorName, nil
}

// ResourceExists returns true if the given resource kind exists
// in the given api groupversion
func ResourceExists(dc discovery.DiscoveryInterface, apiGroupVersion, kind string) (bool, error) {

_, apiLists, err := dc.ServerGroupsAndResources()
if err != nil {
return false, err
}
for _, apiList := range apiLists {
if apiList.GroupVersion == apiGroupVersion {
for _, r := range apiList.APIResources {
if r.Kind == kind {
return true, nil
}
}
}
}
return false, nil
}

// GetPod returns a Pod object that corresponds to the pod in which the code
// is currently running.
// It expects the environment variable POD_NAME to be set by the downwards API.
func GetPod(ctx context.Context, client crclient.Client, ns string) (*corev1.Pod, error) {
if isRunModeLocal() {
return nil, ErrRunLocal
}
podName := os.Getenv(PodNameEnvVar)
if podName == "" {
return nil, fmt.Errorf("required env %s not set, please configure downward API", PodNameEnvVar)
}

logk8sutil.V(1).Info("Found podname", "Pod.Name", podName)

pod := &corev1.Pod{}
key := crclient.ObjectKey{Namespace: ns, Name: podName}
err := client.Get(ctx, key, pod)
if err != nil {
logk8sutil.Error(err, "Failed to get Pod", "Pod.Namespace", ns, "Pod.Name", podName)
return nil, err
}

// .Get() clears the APIVersion and Kind,
// so we need to set them before returning the object.
pod.TypeMeta.APIVersion = "v1"
pod.TypeMeta.Kind = "Pod"

logk8sutil.V(1).Info("Found Pod", "Pod.Namespace", ns, "Pod.Name", pod.Name)

return pod, nil
}

// GetGVKsFromAddToScheme takes in the runtime scheme and filters out all generic apimachinery meta types.
// It returns just the GVK specific to this scheme.
func GetGVKsFromAddToScheme(addToSchemeFunc func(*runtime.Scheme) error) ([]schema.GroupVersionKind, error) {
s := runtime.NewScheme()
err := addToSchemeFunc(s)
if err != nil {
return nil, err
}
schemeAllKnownTypes := s.AllKnownTypes()
ownGVKs := []schema.GroupVersionKind{}
for gvk := range schemeAllKnownTypes {
if !isKubeMetaKind(gvk.Kind) {
ownGVKs = append(ownGVKs, gvk)
}
}

return ownGVKs, nil
}

func isKubeMetaKind(kind string) bool {
if strings.HasSuffix(kind, "List") ||
kind == "PatchOptions" ||
kind == "GetOptions" ||
kind == "DeleteOptions" ||
kind == "ExportOptions" ||
kind == "APIVersions" ||
kind == "APIGroupList" ||
kind == "APIResourceList" ||
kind == "UpdateOptions" ||
kind == "CreateOptions" ||
kind == "Status" ||
kind == "WatchEvent" ||
kind == "ListOptions" ||
kind == "APIGroup" {
return true
}

return false
}

func isRunModeLocal() bool {
return os.Getenv(ForceRunModeEnv) == string(LocalRunMode)
}

// SupportsOwnerReference checks whether a given dependent supports owner references, based on the owner.
// This function performs following checks:
// -- True: Owner is cluster-scoped.
Expand Down
57 changes: 0 additions & 57 deletions internal/util/k8sutil/k8sutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
package k8sutil

import (
"fmt"
"os"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -54,60 +51,6 @@ func TestGetDisplayName(t *testing.T) {
}
}

func TestGetOperatorName(t *testing.T) {
type Output struct {
operatorName string
err error
}

type Scenario struct {
name string
envVarKey string
envVarValue string
expectedOutput Output
}

tests := []Scenario{
{
name: "Simple case",
envVarKey: OperatorNameEnvVar,
envVarValue: "myoperator",
expectedOutput: Output{
operatorName: "myoperator",
err: nil,
},
},
{
name: "Unset env var",
envVarKey: "",
envVarValue: "",
expectedOutput: Output{
operatorName: "",
err: fmt.Errorf("%s must be set", OperatorNameEnvVar),
},
},
{
name: "Empty env var",
envVarKey: OperatorNameEnvVar,
envVarValue: "",
expectedOutput: Output{
operatorName: "",
err: fmt.Errorf("%s must not be empty", OperatorNameEnvVar),
},
},
}

for _, test := range tests {
_ = os.Setenv(test.envVarKey, test.envVarValue)
operatorName, err := GetOperatorName()
if !(operatorName == test.expectedOutput.operatorName && reflect.DeepEqual(err, test.expectedOutput.err)) {
t.Errorf("Test %s failed, expected output: %s,%v; got: %s,%v", test.name,
test.expectedOutput.operatorName, test.expectedOutput.err, operatorName, err)
}
_ = os.Unsetenv(test.envVarKey)
}
}

func TestSupportsOwnerReference(t *testing.T) {
type testcase struct {
name string
Expand Down