diff --git a/internal/k8s/cm.go b/internal/k8s/cm.go deleted file mode 100644 index b1e3786c..00000000 --- a/internal/k8s/cm.go +++ /dev/null @@ -1,44 +0,0 @@ -package k8s - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// ConfigMap represents a Kubernetes ConfigMap -type ConfigMap struct { - *base - Connection -} - -// NewConfigMap returns a new ConfigMap. -func NewConfigMap(c Connection) *ConfigMap { - return &ConfigMap{&base{}, c} -} - -// Get a ConfigMap. -func (c *ConfigMap) Get(ns, n string) (interface{}, error) { - return c.DialOrDie().CoreV1().ConfigMaps(ns).Get(n, metav1.GetOptions{}) -} - -// List all ConfigMaps in a given namespace. -func (c *ConfigMap) List(ns string) (Collection, error) { - opts := metav1.ListOptions{ - LabelSelector: c.labelSelector, - FieldSelector: c.fieldSelector, - } - rr, err := c.DialOrDie().CoreV1().ConfigMaps(ns).List(opts) - if err != nil { - return nil, err - } - cc := make(Collection, len(rr.Items)) - for i, r := range rr.Items { - cc[i] = r - } - - return cc, nil -} - -// Delete a ConfigMap. -func (c *ConfigMap) Delete(ns, n string, cascade, force bool) error { - return c.DialOrDie().CoreV1().ConfigMaps(ns).Delete(n, nil) -} diff --git a/internal/k8s/secret.go b/internal/k8s/secret.go deleted file mode 100644 index 55ce7980..00000000 --- a/internal/k8s/secret.go +++ /dev/null @@ -1,44 +0,0 @@ -package k8s - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Secret represents a Kubernetes Secret. -type Secret struct { - *base - Connection -} - -// NewSecret returns a new Secret. -func NewSecret(c Connection) *Secret { - return &Secret{&base{}, c} -} - -// Get a Secret. -func (s *Secret) Get(ns, n string) (interface{}, error) { - return s.DialOrDie().CoreV1().Secrets(ns).Get(n, metav1.GetOptions{}) -} - -// List all Secrets in a given namespace. -func (s *Secret) List(ns string) (Collection, error) { - opts := metav1.ListOptions{ - LabelSelector: s.labelSelector, - FieldSelector: s.fieldSelector, - } - rr, err := s.DialOrDie().CoreV1().Secrets(ns).List(opts) - if err != nil { - return nil, err - } - cc := make(Collection, len(rr.Items)) - for i, r := range rr.Items { - cc[i] = r - } - - return cc, nil -} - -// Delete a Secret. -func (s *Secret) Delete(ns, n string, cascade, force bool) error { - return s.DialOrDie().CoreV1().Secrets(ns).Delete(n, nil) -} diff --git a/internal/resource/cm.go b/internal/resource/cm.go index 5130f6c5..08317942 100644 --- a/internal/resource/cm.go +++ b/internal/resource/cm.go @@ -1,96 +1,6 @@ package resource -import ( - "log" - "strconv" - - "github.com/derailed/k9s/internal/k8s" - v1 "k8s.io/api/core/v1" -) - -// ConfigMap tracks a kubernetes resource. -type ConfigMap struct { - *Base - instance *v1.ConfigMap -} - // NewConfigMapList returns a new resource list. func NewConfigMapList(c Connection, ns string) List { - return NewList( - ns, - "cm", - NewConfigMap(c), - AllVerbsAccess|DescribeAccess, - ) -} - -// NewConfigMap instantiates a new ConfigMap. -func NewConfigMap(c Connection) *ConfigMap { - m := &ConfigMap{&Base{Connection: c, Resource: k8s.NewConfigMap(c)}, nil} - m.Factory = m - - return m -} - -// New builds a new ConfigMap instance from a k8s resource. -func (r *ConfigMap) New(i interface{}) Columnar { - cm := NewConfigMap(r.Connection) - switch instance := i.(type) { - case *v1.ConfigMap: - cm.instance = instance - case v1.ConfigMap: - cm.instance = &instance - default: - log.Fatalf("Unknown %#v", i) - } - cm.path = cm.namespacedName(cm.instance.ObjectMeta) - - return cm -} - -// Marshal resource to yaml. -func (r *ConfigMap) Marshal(path string) (string, error) { - ns, n := Namespaced(path) - i, err := r.Resource.Get(ns, n) - if err != nil { - return "", err - } - - cm := i.(*v1.ConfigMap) - cm.TypeMeta.APIVersion = "v1" - cm.TypeMeta.Kind = "ConfigMap" - - return r.marshalObject(cm) -} - -// Header return resource header. -func (*ConfigMap) Header(ns string) Row { - hh := Row{} - if ns == AllNamespaces { - hh = append(hh, "NAMESPACE") - } - - return append(hh, "NAME", "DATA", "AGE") -} - -// NumCols designates if column is numerical. -func (*ConfigMap) NumCols(n string) map[string]bool { - return map[string]bool{ - "DATA": true, - } -} - -// Fields retrieves displayable fields. -func (r *ConfigMap) Fields(ns string) Row { - ff := make(Row, 0, len(r.Header(ns))) - i := r.instance - if ns == AllNamespaces { - ff = append(ff, i.Namespace) - } - - return append(ff, - i.Name, - strconv.Itoa(len(i.Data)), - toAge(i.ObjectMeta.CreationTimestamp), - ) + return NewCustomList(c, true, "", "v1/configmaps") } diff --git a/internal/resource/cm_test.go b/internal/resource/cm_test.go deleted file mode 100644 index e8aa7f45..00000000 --- a/internal/resource/cm_test.go +++ /dev/null @@ -1,174 +0,0 @@ -package resource_test - -import ( - "testing" - - "github.com/derailed/k9s/internal/k8s" - "github.com/derailed/k9s/internal/resource" - m "github.com/petergtz/pegomock" - "github.com/stretchr/testify/assert" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func NewConfigMapListWithArgs(ns string, r *resource.ConfigMap) resource.List { - return resource.NewList(ns, "cm", r, resource.AllVerbsAccess|resource.DescribeAccess) -} - -func NewConfigMapWithArgs(rc k8s.Connection, res resource.Cruder) *resource.ConfigMap { - r := &resource.ConfigMap{Base: resource.NewBase(rc, res)} - r.Factory = r - return r -} - -func TestCMFieldsAllNS(t *testing.T) { - r := newConfigMap().Fields(resource.AllNamespaces) - assert.Equal(t, "blee", r[0]) - assert.Equal(t, "fred", r[1]) - assert.Equal(t, "2", r[2]) -} - -func TestCMFields(t *testing.T) { - r := newConfigMap().Fields("blee") - assert.Equal(t, "fred", r[0]) - assert.Equal(t, "2", r[1]) -} - -func TestCMGet(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - m.When(cr.Get("blee", "fred")).ThenReturn(k8sCM(), nil) - - cm := NewConfigMapWithArgs(rc, cr) - ma, err := cm.Get("blee/fred") - - assert.Nil(t, err) - cr.VerifyWasCalledOnce().Get("blee", "fred") - assert.Equal(t, cm.New(k8sCM()), ma) -} - -func TestCMList(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - m.When(cr.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil) - - cm := NewConfigMapWithArgs(rc, cr) - ma, err := cm.List("blee") - - assert.Nil(t, err) - cr.VerifyWasCalledOnce().List("blee") - assert.Equal(t, resource.Columnars{cm.New(k8sCM())}, ma) -} - -func TestCMDelete(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - m.When(cr.Delete("blee", "fred", true, true)).ThenReturn(nil) - - cm := NewConfigMapWithArgs(rc, cr) - - assert.Nil(t, cm.Delete("blee/fred", true, true)) - cr.VerifyWasCalledOnce().Delete("blee", "fred", true, true) -} - -func TestCMMarshal(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - m.When(cr.Get("blee", "fred")).ThenReturn(k8sCM(), nil) - - cm := NewConfigMapWithArgs(rc, cr) - ma, err := cm.Marshal("blee/fred") - - cr.VerifyWasCalledOnce().Get("blee", "fred") - assert.Nil(t, err) - assert.Equal(t, cmYaml(), ma) -} - -func TestCMListHasName(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - - cm := NewConfigMapWithArgs(rc, cr) - l := NewConfigMapListWithArgs("blee", cm) - - assert.Equal(t, "cm", l.GetName()) -} - -func TestCMListHasNamespace(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - - cm := NewConfigMapWithArgs(rc, cr) - l := NewConfigMapListWithArgs("blee", cm) - - assert.Equal(t, "blee", l.GetNamespace()) -} - -func TestCMListHasResource(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - - cm := NewConfigMapWithArgs(rc, cr) - l := NewConfigMapListWithArgs("blee", cm) - - assert.NotNil(t, l.Resource()) -} - -func TestCMListData(t *testing.T) { - rc := NewMockConnection() - cr := NewMockCruder() - m.When(cr.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil) - - cm := NewConfigMapWithArgs(rc, cr) - l := NewConfigMapListWithArgs("blee", cm) - - // Make sure we crn get deltas! - for i := 0; i < 2; i++ { - err := l.Reconcile(nil, nil) - assert.Nil(t, err) - } - - cr.VerifyWasCalled(m.Times(2)).List("blee") - - td := l.Data() - assert.Equal(t, 1, len(td.Rows)) - - assert.Equal(t, "blee", l.GetNamespace()) - row := td.Rows["blee/fred"] - assert.Equal(t, 3, len(row.Deltas)) - for _, d := range row.Deltas { - assert.Equal(t, "", d) - } - assert.Equal(t, resource.Row{"fred", "2"}, row.Fields[:2]) -} - -// Helpers... - -func newConfigMap() resource.Columnar { - rc := NewMockConnection() - return resource.NewConfigMap(rc).New(k8sCM()) -} - -func k8sCM() *v1.ConfigMap { - return &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fred", - Namespace: "blee", - CreationTimestamp: metav1.Time{testTime()}, - }, - Data: map[string]string{"blee": "blee", "duh": "duh"}, - } -} - -func cmYaml() string { - return `apiVersion: v1 -data: - blee: blee - duh: duh -kind: ConfigMap -metadata: - creationTimestamp: "2018-12-14T17:36:43Z" - name: fred - namespace: blee -` -} diff --git a/internal/resource/secret.go b/internal/resource/secret.go index ba02f54c..26adbb1d 100644 --- a/internal/resource/secret.go +++ b/internal/resource/secret.go @@ -1,97 +1,6 @@ package resource -import ( - "strconv" - - "github.com/derailed/k9s/internal/k8s" - "github.com/rs/zerolog/log" - v1 "k8s.io/api/core/v1" -) - -// Secret tracks a kubernetes resource. -type Secret struct { - *Base - instance *v1.Secret -} - // NewSecretList returns a new resource list. func NewSecretList(c Connection, ns string) List { - return NewList( - ns, - "secret", - NewSecret(c), - AllVerbsAccess|DescribeAccess, - ) -} - -// NewSecret instantiates a new Secret. -func NewSecret(c Connection) *Secret { - s := &Secret{&Base{Connection: c, Resource: k8s.NewSecret(c)}, nil} - s.Factory = s - - return s -} - -// New builds a new Secret instance from a k8s resource. -func (r *Secret) New(i interface{}) Columnar { - c := NewSecret(r.Connection) - switch instance := i.(type) { - case *v1.Secret: - c.instance = instance - case v1.Secret: - c.instance = &instance - default: - log.Fatal().Msgf("unknown Secret type %#v", i) - } - c.path = c.namespacedName(c.instance.ObjectMeta) - - return c -} - -// Marshal resource to yaml. -func (r *Secret) Marshal(path string) (string, error) { - ns, n := Namespaced(path) - i, err := r.Resource.Get(ns, n) - if err != nil { - return "", err - } - - sec := i.(*v1.Secret) - sec.TypeMeta.APIVersion = "v1" - sec.TypeMeta.Kind = "Secret" - - return r.marshalObject(sec) -} - -// Header return resource header. -func (*Secret) Header(ns string) Row { - hh := Row{} - if ns == AllNamespaces { - hh = append(hh, "NAMESPACE") - } - - return append(hh, "NAME", "TYPE", "DATA", "AGE") -} - -// NumCols designates if column is numerical. -func (*Secret) NumCols(n string) map[string]bool { - return map[string]bool{ - "DATA": true, - } -} - -// Fields retrieves displayable fields. -func (r *Secret) Fields(ns string) Row { - ff := make(Row, 0, len(r.Header(ns))) - i := r.instance - if ns == AllNamespaces { - ff = append(ff, i.Namespace) - } - - return append(ff, - i.Name, - string(i.Type), - strconv.Itoa(len(i.Data)), - toAge(i.ObjectMeta.CreationTimestamp), - ) + return NewCustomList(c, true, "", "v1/secrets") } diff --git a/internal/resource/secret_test.go b/internal/resource/secret_test.go deleted file mode 100644 index 9ad2bb2e..00000000 --- a/internal/resource/secret_test.go +++ /dev/null @@ -1,187 +0,0 @@ -package resource_test - -import ( - "testing" - - "github.com/derailed/k9s/internal/k8s" - "github.com/derailed/k9s/internal/resource" - m "github.com/petergtz/pegomock" - "github.com/stretchr/testify/assert" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func NewSecretListWithArgs(ns string, r *resource.Secret) resource.List { - return resource.NewList(ns, "secret", r, resource.AllVerbsAccess|resource.DescribeAccess) -} - -func NewSecretWithArgs(conn k8s.Connection, res resource.Cruder) *resource.Secret { - r := &resource.Secret{Base: resource.NewBase(conn, res)} - r.Factory = r - return r -} - -func TestSecretHeader(t *testing.T) { - assert.Equal(t, - resource.Row{"NAME", "TYPE", "DATA", "AGE"}, - newSecret().Header(resource.DefaultNamespace), - ) -} - -func TestSecretHeaderAllNS(t *testing.T) { - assert.Equal(t, - resource.Row{"NAMESPACE", "NAME", "TYPE", "DATA", "AGE"}, - newSecret().Header(resource.AllNamespaces), - ) -} - -func TestSecretFieldsAllNS(t *testing.T) { - r := newSecret().Fields(resource.AllNamespaces) - assert.Equal(t, "blee", r[0]) - assert.Equal(t, "fred", r[1]) - assert.Equal(t, "Opaque", r[2]) - assert.Equal(t, "2", r[3]) -} - -func TestSecretFields(t *testing.T) { - r := newSecret().Fields("blee") - assert.Equal(t, "fred", r[0]) - assert.Equal(t, "Opaque", r[1]) - assert.Equal(t, "2", r[2]) -} - -func TestSecretGet(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - m.When(mr.Get("blee", "fred")).ThenReturn(k8sSecret(), nil) - - cm := NewSecretWithArgs(mc, mr) - ma, err := cm.Get("blee/fred") - - assert.Nil(t, err) - mr.VerifyWasCalledOnce().Get("blee", "fred") - assert.Equal(t, cm.New(k8sSecret()), ma) -} - -func TestSecretList(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - m.When(mr.List("blee")).ThenReturn(k8s.Collection{*k8sSecret()}, nil) - - cm := NewSecretWithArgs(mc, mr) - ma, err := cm.List("blee") - - assert.Nil(t, err) - mr.VerifyWasCalledOnce().List("blee") - assert.Equal(t, resource.Columnars{cm.New(k8sSecret())}, ma) -} - -func TestSecretDelete(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - m.When(mr.Delete("blee", "fred", true, true)).ThenReturn(nil) - - cm := NewSecretWithArgs(mc, mr) - - assert.Nil(t, cm.Delete("blee/fred", true, true)) - mr.VerifyWasCalledOnce().Delete("blee", "fred", true, true) -} - -func TestSecretMarshal(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - m.When(mr.Get("blee", "fred")).ThenReturn(k8sSecret(), nil) - - cm := NewSecretWithArgs(mc, mr) - ma, err := cm.Marshal("blee/fred") - - mr.VerifyWasCalledOnce().Get("blee", "fred") - assert.Nil(t, err) - assert.Equal(t, secretYaml(), ma) -} - -func TestSecretListHasName(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - - l := NewSecretListWithArgs("blee", NewSecretWithArgs(mc, mr)) - assert.Equal(t, "secret", l.GetName()) -} - -func TestSecretListHasNamespace(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - l := NewSecretListWithArgs("blee", NewSecretWithArgs(mc, mr)) - assert.Equal(t, "blee", l.GetNamespace()) -} - -func TestSecretListHasResource(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - l := NewSecretListWithArgs("blee", NewSecretWithArgs(mc, mr)) - assert.NotNil(t, l.Resource()) -} - -func TestSecretListData(t *testing.T) { - mc := NewMockConnection() - mr := NewMockCruder() - m.When(mr.List("blee")).ThenReturn(k8s.Collection{*k8sSecret()}, nil) - - l := NewSecretListWithArgs("blee", NewSecretWithArgs(mc, mr)) - // Make sure we mrn get deltas! - for i := 0; i < 2; i++ { - err := l.Reconcile(nil, nil) - assert.Nil(t, err) - } - - mr.VerifyWasCalled(m.Times(2)).List("blee") - - td := l.Data() - assert.Equal(t, 1, len(td.Rows)) - - assert.Equal(t, "blee", l.GetNamespace()) - row := td.Rows["blee/fred"] - assert.Equal(t, 4, len(row.Deltas)) - for _, d := range row.Deltas { - assert.Equal(t, "", d) - } - assert.Equal(t, resource.Row{"fred", "Opaque", "2"}, row.Fields[:3]) -} - -// Helpers... - -func newSecret() resource.Columnar { - mc := NewMockConnection() - return resource.NewSecret(mc).New(k8sSecret()) -} - -func k8sSecret() *v1.Secret { - secrets := map[string]string{"blee": "blee", "duh": "duh"} - data := map[string][]byte{} - for k, v := range secrets { - data[k] = []byte(v) - } - return &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fred", - Namespace: "blee", - CreationTimestamp: metav1.Time{testTime()}, - }, - Type: v1.SecretTypeOpaque, - Data: data, - } -} - -func secretYaml() string { - return `apiVersion: v1 -data: - blee: YmxlZQ== - duh: ZHVo -kind: Secret -metadata: - creationTimestamp: "2018-12-14T17:36:43Z" - name: fred - namespace: blee -type: Opaque -` -}