diff --git a/.gitignore b/.gitignore index d110969..51a1a3b 100644 --- a/.gitignore +++ b/.gitignore @@ -333,3 +333,6 @@ ASALocalRun/ bin/ vendor/ _dist/ +c.out +coverage.html + diff --git a/Gopkg.lock b/Gopkg.lock index e00a06d..b0f7f6b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -72,6 +72,14 @@ pruneopts = "UT" revision = "5a15988393449988e8d4ea493df73df2684675f2" +[[projects]] + digest = "1:f1f2bd73c025d24c3b93abf6364bccb802cf2fdedaa44360804c67800e8fab8d" + name = "github.com/evanphx/json-patch" + packages = ["."] + pruneopts = "UT" + revision = "72bf35d0ff611848c1dc9df0f976c81192392fa5" + version = "v4.1.0" + [[projects]] digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" name = "github.com/fsnotify/fsnotify" @@ -273,6 +281,14 @@ revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1" +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + [[projects]] digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4" name = "github.com/prometheus/client_golang" @@ -362,6 +378,14 @@ revision = "6d33b5a963d922d182c91e8a1c88d81fd150cfd4" version = "v1.3.1" +[[projects]] + digest = "1:25f2747b063c0a656195ef85413cef8c9f2bbe128deab7d39563a6ca1e536070" + name = "github.com/stretchr/testify" + packages = ["assert"] + pruneopts = "UT" + revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0" + version = "v1.1.4" + [[projects]] digest = "1:d1816f8f4877e87cf0a80a25fbc0e7c7a6937bd728ccbf85e2c151c792445a1b" name = "github.com/thoas/go-funk" @@ -592,44 +616,78 @@ version = "kubernetes-1.13.0" [[projects]] - digest = "1:032912062bdb7ab2fd018235e24831f9eea6735ba875886323eae616c6088961" + digest = "1:ccdff5d2d86fb5dd1a4f9c217c574ab6965d91f46d9288f71dd565aa9760cc58" name = "k8s.io/client-go" packages = [ "discovery", + "discovery/fake", "kubernetes", + "kubernetes/fake", "kubernetes/scheme", "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1alpha1/fake", "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/admissionregistration/v1beta1/fake", "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1/fake", "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta1/fake", "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/apps/v1beta2/fake", "kubernetes/typed/auditregistration/v1alpha1", + "kubernetes/typed/auditregistration/v1alpha1/fake", "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1/fake", "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authentication/v1beta1/fake", "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1/fake", "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/authorization/v1beta1/fake", "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v1/fake", "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/autoscaling/v2beta1/fake", "kubernetes/typed/autoscaling/v2beta2", + "kubernetes/typed/autoscaling/v2beta2/fake", "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1/fake", "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v1beta1/fake", "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/batch/v2alpha1/fake", "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/certificates/v1beta1/fake", "kubernetes/typed/coordination/v1beta1", + "kubernetes/typed/coordination/v1beta1/fake", "kubernetes/typed/core/v1", + "kubernetes/typed/core/v1/fake", "kubernetes/typed/events/v1beta1", + "kubernetes/typed/events/v1beta1/fake", "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/extensions/v1beta1/fake", "kubernetes/typed/networking/v1", + "kubernetes/typed/networking/v1/fake", "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/policy/v1beta1/fake", "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1/fake", "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1alpha1/fake", "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/rbac/v1beta1/fake", "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/scheduling/v1alpha1/fake", "kubernetes/typed/scheduling/v1beta1", + "kubernetes/typed/scheduling/v1beta1/fake", "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/settings/v1alpha1/fake", "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1/fake", "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1alpha1/fake", "kubernetes/typed/storage/v1beta1", + "kubernetes/typed/storage/v1beta1/fake", "pkg/apis/clientauthentication", "pkg/apis/clientauthentication/v1alpha1", "pkg/apis/clientauthentication/v1beta1", @@ -637,6 +695,7 @@ "plugin/pkg/client/auth/exec", "rest", "rest/watch", + "testing", "tools/auth", "tools/cache", "tools/clientcmd", @@ -706,6 +765,7 @@ "github.com/prometheus/client_golang/prometheus/promhttp", "github.com/spf13/pflag", "github.com/spf13/viper", + "github.com/stretchr/testify/assert", "github.com/thoas/go-funk", "github.com/tidwall/gjson", "k8s.io/api/core/v1", @@ -713,6 +773,7 @@ "k8s.io/apimachinery/pkg/apis/meta/v1", "k8s.io/apimachinery/pkg/fields", "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/fake", "k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/rest", "k8s.io/client-go/tools/cache", diff --git a/Gopkg.toml b/Gopkg.toml index 9f96244..b450168 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -80,3 +80,7 @@ [[constraint]] branch = "master" name = "github.com/dimiro1/health" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.1.4" diff --git a/Makefile b/Makefile index 9b4305c..0f66e29 100644 --- a/Makefile +++ b/Makefile @@ -74,10 +74,11 @@ docker-publish-latest: docker push oxynozeta/kubernetes-tagger:latest test: dep ## Run unittests - $(GO) test -short ${PKG_LIST} + $(GO) test -short -cover -coverprofile=c.out ${PKG_LIST} -race: dep ## Run data race detector - $(GO) test -race -short ${PKG_LIST} +.PHONY: coverage-report +coverage-report: + $(GO) tool cover -html=c.out -o coverage.html .PHONY: clean clean: diff --git a/pkg/kubernetes-tagger/business/model.go b/pkg/kubernetes-tagger/business/model.go index 536c18e..ee65c42 100644 --- a/pkg/kubernetes-tagger/business/model.go +++ b/pkg/kubernetes-tagger/business/model.go @@ -56,6 +56,12 @@ func (context *Context) runForPV(pv *v1.PersistentVolume) error { return nil } + // Check if configuration is valid before continue + err = resource.CheckIfConfigurationValid() + if err != nil { + return err + } + // Get actual tags actualTags, err := resource.GetActualTags() if err != nil { diff --git a/pkg/kubernetes-tagger/resources/awsvolume.go b/pkg/kubernetes-tagger/resources/awsvolume.go index b8baffd..536e80b 100644 --- a/pkg/kubernetes-tagger/resources/awsvolume.go +++ b/pkg/kubernetes-tagger/resources/awsvolume.go @@ -1,6 +1,7 @@ package resources import ( + "errors" "fmt" "net/url" "strings" @@ -12,11 +13,15 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/oxyno-zeta/kubernetes-tagger/pkg/kubernetes-tagger/config" v1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) +// ErrEmptyAWSConfiguration Error Empty AWS Configuration +var ErrEmptyAWSConfiguration = errors.New("AWS configuration is empty") + +// ErrEmptyAWSRegionConfiguration Error Empty AWS Region Configuration +var ErrEmptyAWSRegionConfiguration = errors.New("AWS Region is empty in configuration") + // AWSVolume AWS Volume type AWSVolume struct { resourceType string @@ -28,12 +33,6 @@ type AWSVolume struct { log *logrus.Entry } -// AWSVolumeResourceType AWS Volume Resource Type -const AWSVolumeResourceType = "volume" - -// AWSResourcePlatform AWS Resource Platform -const AWSResourcePlatform = "aws" - // Type Get type func (av *AWSVolume) Type() string { return av.resourceType @@ -84,9 +83,20 @@ func isAWSVolumeResource(pv *v1.PersistentVolume) bool { return pv.Spec.AWSElasticBlockStore != nil } +// CheckIfConfigurationValid Check if configuration is valid +func (av *AWSVolume) CheckIfConfigurationValid() error { + if av.awsConfig == nil { + return ErrEmptyAWSConfiguration + } + if av.awsConfig.Region == "" { + return ErrEmptyAWSRegionConfiguration + } + return nil +} + // GetAvailableTagValues Get available tags func (av *AWSVolume) GetAvailableTagValues() (map[string]interface{}, error) { - pvc, err := av.getPersistentVolumeClaim() + pvc, err := getPersistentVolumeClaim(av.persistentVolume, av.k8sClient) if err != nil { return nil, err } @@ -222,16 +232,3 @@ func (av *AWSVolume) getAWSEC2Client() (*ec2.EC2, error) { svc := ec2.New(sess) return svc, nil } - -func (av *AWSVolume) getPersistentVolumeClaim() (*v1.PersistentVolumeClaim, error) { - claimRef := av.persistentVolume.Spec.ClaimRef - if claimRef == nil { - return nil, nil - } - - pvc, err := av.k8sClient.CoreV1().PersistentVolumeClaims(claimRef.Namespace).Get(claimRef.Name, metav1.GetOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { - return nil, err - } - return pvc, nil -} diff --git a/pkg/kubernetes-tagger/resources/model.go b/pkg/kubernetes-tagger/resources/model.go index 5e2801c..b1e164c 100644 --- a/pkg/kubernetes-tagger/resources/model.go +++ b/pkg/kubernetes-tagger/resources/model.go @@ -23,6 +23,7 @@ type Resource interface { Type() string Platform() string CanBeProcessed() bool + CheckIfConfigurationValid() error GetAvailableTagValues() (map[string]interface{}, error) GetActualTags() ([]*Tag, error) ManageTags(delta *TagDelta) error diff --git a/pkg/kubernetes-tagger/resources/utils.go b/pkg/kubernetes-tagger/resources/utils.go new file mode 100644 index 0000000..c6c3140 --- /dev/null +++ b/pkg/kubernetes-tagger/resources/utils.go @@ -0,0 +1,27 @@ +package resources + +import ( + v1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// AWSVolumeResourceType AWS Volume Resource Type +const AWSVolumeResourceType = "volume" + +// AWSResourcePlatform AWS Resource Platform +const AWSResourcePlatform = "aws" + +func getPersistentVolumeClaim(persistentVolume *v1.PersistentVolume, k8sClient kubernetes.Interface) (*v1.PersistentVolumeClaim, error) { + claimRef := persistentVolume.Spec.ClaimRef + if claimRef == nil { + return nil, nil + } + + pvc, err := k8sClient.CoreV1().PersistentVolumeClaims(claimRef.Namespace).Get(claimRef.Name, metav1.GetOptions{}) + if err != nil && !k8serrors.IsNotFound(err) { + return nil, err + } + return pvc, nil +} diff --git a/pkg/kubernetes-tagger/resources/utils_test.go b/pkg/kubernetes-tagger/resources/utils_test.go new file mode 100644 index 0000000..ed58b5d --- /dev/null +++ b/pkg/kubernetes-tagger/resources/utils_test.go @@ -0,0 +1,56 @@ +package resources + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + testclient "k8s.io/client-go/kubernetes/fake" +) + +func TestGetPersistentVolumeClaimWithoutClaimRef(t *testing.T) { + spec := v1.PersistentVolumeSpec{ClaimRef: nil} + pv := v1.PersistentVolume{Spec: spec} + + // Call code + res, err := getPersistentVolumeClaim(&pv, nil) + + assert.Nil(t, res) + assert.Nil(t, err) +} + +func TestGetPersistentVolumeClaimWithClaimNotFound(t *testing.T) { + claimRef := v1.ObjectReference{Namespace: "test-claim-ref-namespace", Name: "test-claim-ref-name"} + spec := v1.PersistentVolumeSpec{ClaimRef: &claimRef} + pv := v1.PersistentVolume{Spec: spec} + + client := testclient.NewSimpleClientset() + + // Call code + res, err := getPersistentVolumeClaim(&pv, client) + + assert.Nil(t, res) + assert.Nil(t, err) +} + +func TestGetPersistentVolumeClaimWithClaimFound(t *testing.T) { + claimRefNamespace := "test-claim-ref-namespace" + claimRefName := "test-claim-ref-name" + claimRef := v1.ObjectReference{Namespace: claimRefNamespace, Name: claimRefName} + spec := v1.PersistentVolumeSpec{ClaimRef: &claimRef} + pv := v1.PersistentVolume{Spec: spec} + + // PVC + pvc := &v1.PersistentVolumeClaim{ObjectMeta: metav1.ObjectMeta{Name: claimRefName, Namespace: claimRefNamespace}} + + client := testclient.NewSimpleClientset(pvc) + + // Call code + res, err := getPersistentVolumeClaim(&pv, client) + + assert.NotNil(t, res) + assert.Nil(t, err) + assert.Equal(t, pvc, res) +} diff --git a/pkg/kubernetes-tagger/version/version_test.go b/pkg/kubernetes-tagger/version/version_test.go new file mode 100644 index 0000000..1cdf863 --- /dev/null +++ b/pkg/kubernetes-tagger/version/version_test.go @@ -0,0 +1,43 @@ +package version + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetVersionWithDefault(t *testing.T) { + // Call code + res := GetVersion() + + assert.Exactly(t, "-unreleased", res.Version) + assert.Empty(t, res.GitCommit) + assert.Empty(t, res.BuildDate) +} + +func TestGetVersionNotReleased(t *testing.T) { + Version = "version" + GitCommit = "sha1" + BuildDate = "04-03-2019" + + // Call code + res := GetVersion() + + assert.Exactly(t, "version-unreleased", res.Version) + assert.Exactly(t, "sha1", res.GitCommit) + assert.Exactly(t, "04-03-2019", res.BuildDate) +} + +func TestGetVersionReleased(t *testing.T) { + Version = "version" + GitCommit = "sha1" + BuildDate = "04-03-2019" + Metadata = "" + + // Call code + res := GetVersion() + + assert.Exactly(t, "version", res.Version) + assert.Exactly(t, "sha1", res.GitCommit) + assert.Exactly(t, "04-03-2019", res.BuildDate) +}