From f2bb03aa22b26791afc03fc52dc1af3afb2fa1f9 Mon Sep 17 00:00:00 2001 From: Jack Francis Date: Tue, 28 Jun 2016 17:13:30 -0700 Subject: [PATCH 1/4] basic data structure in place --- api/swagger-spec/swagger.yml | 63 +++- boot.go | 19 +- boot_test.go | 3 +- data/available_component_versions.go | 17 +- data/available_versions.go | 3 - data/available_versions_test.go | 64 ++++ data/cluster_id.go | 5 +- data/data.go | 94 ++++-- data/data_test.go | 71 +--- data/installed_data.go | 10 +- glide.lock | 40 ++- glide.yaml | 2 +- handlers/handlers.go | 27 +- handlers/handlers_test.go | 46 ++- jobs/jobs.go | 44 +-- k8s/interfaces.go | 72 ++++ k8s/k8s.go | 350 ++++++++++++++++++++ {data => k8s}/kube_secret_getter_creator.go | 4 +- mocks/mocks.go | 51 +++ pkg/swagger/models/data.go | 5 +- pkg/swagger/models/doctor_info.go | 75 ++++- pkg/swagger/models/k8s_resource.go | 43 +++ pkg/swagger/models/namespace.go | 265 +++++++++++++++ pkg/swagger/models/version.go | 5 +- 24 files changed, 1174 insertions(+), 204 deletions(-) create mode 100644 k8s/interfaces.go create mode 100644 k8s/k8s.go rename {data => k8s}/kube_secret_getter_creator.go (93%) create mode 100644 pkg/swagger/models/k8s_resource.go create mode 100644 pkg/swagger/models/namespace.go diff --git a/api/swagger-spec/swagger.yml b/api/swagger-spec/swagger.yml index 93b7987..357b38c 100644 --- a/api/swagger-spec/swagger.yml +++ b/api/swagger-spec/swagger.yml @@ -311,13 +311,72 @@ definitions: type: array items: $ref: "#/definitions/componentVersion" + k8sResource: + type: object + required: + - data + properties: + data: + type: object + namespace: + type: object + required: + - name + - daemonSets + - deployments + - events + - pods + - replicaSets + - replicationControllers + - services + properties: + name: + type: string + daemonSets: + type: array + items: + $ref: "#/definitions/k8sResource" + deployments: + type: array + items: + $ref: "#/definitions/k8sResource" + events: + type: array + items: + $ref: "#/definitions/k8sResource" + pods: + type: array + items: + $ref: "#/definitions/k8sResource" + replicaSets: + type: array + items: + $ref: "#/definitions/k8sResource" + replicationControllers: + type: array + items: + $ref: "#/definitions/k8sResource" + services: + type: array + items: + $ref: "#/definitions/k8sResource" doctorInfo: type: object required: - - cluster + - workflow + - nodes + - namespaces properties: - cluster: + workflow: $ref: "#/definitions/cluster" + nodes: + type: array + items: + $ref: "#/definitions/k8sResource" + namespaces: + type: array + items: + $ref: "#/definitions/namespace" componentVersion: type: object properties: diff --git a/boot.go b/boot.go index 4bd18d2..ee201a4 100644 --- a/boot.go +++ b/boot.go @@ -10,6 +10,7 @@ import ( "github.com/deis/workflow-manager/data" "github.com/deis/workflow-manager/handlers" "github.com/deis/workflow-manager/jobs" + "github.com/deis/workflow-manager/k8s" "github.com/gorilla/mux" kcl "k8s.io/kubernetes/pkg/client/unversioned" ) @@ -23,25 +24,20 @@ func main() { if err != nil { log.Fatalf("Error creating new swagger api client (%s)", err) } - secretInterface := kubeClient.Secrets(config.Spec.DeisNamespace) - rcInterface := kubeClient.ReplicationControllers(config.Spec.DeisNamespace) - clusterID := data.NewClusterIDFromPersistentStorage(secretInterface) - installedDeisData := data.NewInstalledDeisData(rcInterface) + deisK8sResources := k8s.NewResourceInterfaceNamespaced(kubeClient, config.Spec.DeisNamespace) + clusterID := data.NewClusterIDFromPersistentStorage(deisK8sResources.Secrets()) + installedDeisData := data.NewInstalledDeisData(deisK8sResources) availableVersion := data.NewAvailableVersionsFromAPI( apiClient, config.Spec.VersionsAPIURL, - secretInterface, - rcInterface, ) - availableComponentVersion := data.NewLatestReleasedComponent(secretInterface, rcInterface, availableVersion) + availableComponentVersion := data.NewLatestReleasedComponent(deisK8sResources, availableVersion) pollDur := time.Duration(config.Spec.Polling) * time.Second // we want to do the following jobs according to our remote API interval: // 1. get latest stable deis component versions // 2. send diagnostic data, if appropriate glvdPeriodic := jobs.NewGetLatestVersionDataPeriodic( - secretInterface, - rcInterface, installedDeisData, clusterID, availableVersion, @@ -51,8 +47,7 @@ func main() { svPeriodic := jobs.NewSendVersionsPeriodic( apiClient, - secretInterface, - rcInterface, + deisK8sResources, availableVersion, pollDur, ) @@ -62,7 +57,7 @@ func main() { defer close(ch) // Get a new router, with handler functions - r := handlers.RegisterRoutes(mux.NewRouter(), secretInterface, rcInterface, availableVersion) + r := handlers.RegisterRoutes(mux.NewRouter(), availableVersion, deisK8sResources) // Bind to a port and pass our router in hostStr := fmt.Sprintf(":%s", config.Spec.Port) log.Printf("Serving on %s", hostStr) diff --git a/boot_test.go b/boot_test.go index b34ebb7..74798ac 100644 --- a/boot_test.go +++ b/boot_test.go @@ -23,16 +23,15 @@ func newServer(apiClient *apiclient.WorkflowManager) *httptest.Server { mocks.InstalledMockData{}, &mocks.ClusterIDMockData{}, mocks.LatestMockData{}, - data.NewFakeKubeSecretGetterCreator(nil, nil), ) r.Handle("/components", compHdl) idHdl := handlers.IDHandler(&mocks.ClusterIDMockData{}) r.Handle("/id", idHdl) docHdl := handlers.DoctorHandler( mocks.InstalledMockData{}, + mocks.RunningK8sMockData{}, // TODO: mock k8s node data &mocks.ClusterIDMockData{}, mocks.LatestMockData{}, - data.NewFakeKubeSecretGetterCreator(nil, nil), apiClient, ) r.Handle("/doctor", docHdl).Methods("POST") diff --git a/data/available_component_versions.go b/data/available_component_versions.go index 940e204..9c71b43 100644 --- a/data/available_component_versions.go +++ b/data/available_component_versions.go @@ -1,7 +1,7 @@ package data import ( - "github.com/arschles/kubeapp/api/rc" + "github.com/deis/workflow-manager/k8s" "github.com/deis/workflow-manager/pkg/swagger/models" ) @@ -13,21 +13,18 @@ type AvailableComponentVersion interface { // latestReleasedComponent fulfills the AvailableComponentVersion interface type latestReleasedComponent struct { - secretGetterCreator KubeSecretGetterCreator - rcLister rc.Lister - availableVersions AvailableVersions + k8sResources *k8s.ResourceInterfaceNamespaced + availableVersions AvailableVersions } // NewLatestReleasedComponent creates a new AvailableComponentVersion that gets the latest released component using sgc as the implementation to get and create secrets func NewLatestReleasedComponent( - sgc KubeSecretGetterCreator, - rcl rc.Lister, + ri *k8s.ResourceInterfaceNamespaced, availableVersions AvailableVersions, ) AvailableComponentVersion { return &latestReleasedComponent{ - secretGetterCreator: sgc, - rcLister: rcl, - availableVersions: availableVersions, + k8sResources: ri, + availableVersions: availableVersions, } } @@ -35,8 +32,6 @@ func NewLatestReleasedComponent( func (c *latestReleasedComponent) Get(component string, cluster models.Cluster) (models.Version, error) { version, err := GetLatestVersion( component, - c.secretGetterCreator, - c.rcLister, cluster, c.availableVersions, ) diff --git a/data/available_versions.go b/data/available_versions.go index d44b339..00dc563 100644 --- a/data/available_versions.go +++ b/data/available_versions.go @@ -3,7 +3,6 @@ package data import ( "sync" - "github.com/arschles/kubeapp/api/rc" "github.com/deis/workflow-manager/config" apiclient "github.com/deis/workflow-manager/pkg/swagger/client" "github.com/deis/workflow-manager/pkg/swagger/client/operations" @@ -31,8 +30,6 @@ type availableVersionsFromAPI struct { func NewAvailableVersionsFromAPI( apiClient *apiclient.WorkflowManager, baseVersionsURL string, - secretGetterCreator KubeSecretGetterCreator, - rcLister rc.Lister, ) AvailableVersions { if baseVersionsURL == "" { baseVersionsURL = config.Spec.VersionsAPIURL diff --git a/data/available_versions_test.go b/data/available_versions_test.go index b44de60..9705771 100644 --- a/data/available_versions_test.go +++ b/data/available_versions_test.go @@ -2,6 +2,7 @@ package data import ( "encoding/json" + "fmt" "net/http" "net/http/httptest" "sync" @@ -13,6 +14,69 @@ import ( "github.com/deis/workflow-manager/pkg/swagger/models" ) +// Creating a novel mock struct that fulfills the AvailableVersions interface +type testAvailableVersions struct{} + +func (a testAvailableVersions) Refresh(cluster models.Cluster) ([]models.ComponentVersion, error) { + data := getMockComponentVersions() + var componentVersions []models.ComponentVersion + _ = json.Unmarshal(data, &componentVersions) + return componentVersions, nil +} + +func (a testAvailableVersions) Store(c []models.ComponentVersion) { + return +} + +func (a testAvailableVersions) Cached() []models.ComponentVersion { + return nil +} + +// Creating another mock struct that fulfills the AvailableVersions interface +type shouldBypassAvailableVersions struct{} + +func (a shouldBypassAvailableVersions) Refresh(cluster models.Cluster) ([]models.ComponentVersion, error) { + var componentVersions []models.ComponentVersion + data := []byte(fmt.Sprintf(`[{ + "components": [ + { + "component": { + "name": "bypass me", + "description": "bypass me" + }, + "version": { + "version": "v2-bypass" + } + } + ] + }]`)) + _ = json.Unmarshal(data, &componentVersions) + return componentVersions, nil +} + +func (a shouldBypassAvailableVersions) Store(c []models.ComponentVersion) { + return +} + +func (a shouldBypassAvailableVersions) Cached() []models.ComponentVersion { + return nil +} + +// Calls GetAvailableVersions twice, the first time we expect our passed-in struct w/ Refresh() method +// to be invoked, the 2nd time we expect to receive the same value back (cached in memory) +// and for the passed-in Refresh() method to be ignored +func TestGetAvailableVersions(t *testing.T) { + mock := getMockComponentVersions() + var mockVersions []models.ComponentVersion + assert.NoErr(t, json.Unmarshal(mock, &mockVersions)) + versions, err := GetAvailableVersions(testAvailableVersions{}, models.Cluster{}) + assert.NoErr(t, err) + assert.Equal(t, versions, mockVersions, "component versions data") + versions, err = GetAvailableVersions(shouldBypassAvailableVersions{}, models.Cluster{}) + assert.NoErr(t, err) + assert.Equal(t, versions, mockVersions, "component versions data") +} + func TestRefreshAvailableVersions(t *testing.T) { desc := "this is test1" updAvail := "nothing" diff --git a/data/cluster_id.go b/data/cluster_id.go index 3e04640..352810c 100644 --- a/data/cluster_id.go +++ b/data/cluster_id.go @@ -3,6 +3,7 @@ package data import ( "sync" + "github.com/deis/workflow-manager/k8s" "github.com/satori/go.uuid" "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" @@ -36,11 +37,11 @@ func GetID(id ClusterID) (string, error) { type clusterIDFromPersistentStorage struct { rwm *sync.RWMutex cache string - secretGetterCreator KubeSecretGetterCreator + secretGetterCreator k8s.KubeSecretGetterCreator } // NewClusterIDFromPersistentStorage returns a new ClusterID implementation that uses the kubernetes API to get its cluster information -func NewClusterIDFromPersistentStorage(sgc KubeSecretGetterCreator) ClusterID { +func NewClusterIDFromPersistentStorage(sgc k8s.KubeSecretGetterCreator) ClusterID { return &clusterIDFromPersistentStorage{ rwm: new(sync.RWMutex), cache: "", diff --git a/data/data.go b/data/data.go index 459f822..8375a3e 100644 --- a/data/data.go +++ b/data/data.go @@ -3,12 +3,12 @@ package data import ( "encoding/json" "fmt" + "log" "strings" - "github.com/arschles/kubeapp/api/rc" + "github.com/deis/workflow-manager/config" + "github.com/deis/workflow-manager/k8s" "github.com/deis/workflow-manager/pkg/swagger/models" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/labels" ) const ( @@ -21,7 +21,6 @@ func GetCluster( c InstalledData, i ClusterID, v AvailableComponentVersion, - secretGetterCreator KubeSecretGetterCreator, ) (models.Cluster, error) { // Populate cluster object with installed components @@ -29,9 +28,9 @@ func GetCluster( if err != nil { return models.Cluster{}, err } - err = AddUpdateData(&cluster, v, secretGetterCreator) + err = AddUpdateData(&cluster, v) if err != nil { - return models.Cluster{}, err + log.Println("unable to decorate cluster data with available updates data") } // Get the cluster ID id, err := GetID(i) @@ -45,7 +44,7 @@ func GetCluster( // AddUpdateData adds UpdateAvailable field data to cluster components // Any cluster object modifications are made "in-place" -func AddUpdateData(c *models.Cluster, v AvailableComponentVersion, secretGetterCreator KubeSecretGetterCreator) error { +func AddUpdateData(c *models.Cluster, v AvailableComponentVersion) error { // Determine if any components have an available update for i, component := range c.Components { installed := component.Version.Version @@ -93,8 +92,6 @@ func GetInstalled(g InstalledData) (models.Cluster, error) { // GetLatestVersion returns the latest known version of a deis component func GetLatestVersion( component string, - secretGetterCreator KubeSecretGetterCreator, - rcLister rc.Lister, cluster models.Cluster, availVsns AvailableVersions, ) (models.Version, error) { @@ -139,35 +136,80 @@ func NewestSemVer(v1 string, v2 string) (string, error) { return v1, nil } -// getRCItems is a helper function that returns a slice of -// ReplicationController objects given a rc.Lister interface -func getRCItems(rcLister rc.Lister) ([]api.ReplicationController, error) { - rcs, err := rcLister.List(api.ListOptions{ - LabelSelector: labels.Everything(), - }) - if err != nil { - return []api.ReplicationController{}, err - } - return rcs.Items, nil -} - // GetDoctorInfo collects doctor info and return DoctorInfo struct func GetDoctorInfo( - c InstalledData, + c InstalledData, // workflow cluster data + k k8s.RunningK8sData, // k8s data i ClusterID, v AvailableComponentVersion, - secretGetterCreator KubeSecretGetterCreator, ) (models.DoctorInfo, error) { - cluster, err := GetCluster(c, i, v, secretGetterCreator) + cluster, err := GetCluster(c, i, v) if err != nil { - return models.DoctorInfo{}, err + log.Println("unable to get workflow cluster data") } + nodes := getK8sNodes(k) + var namespaces []*models.Namespace + namespaces = append(namespaces, getK8sDeisNamespace(k)) doctor := models.DoctorInfo{ - Cluster: &cluster, + Workflow: &cluster, + Nodes: nodes, + Namespaces: namespaces, } return doctor, nil } +// getK8sDeisNamespace is a helper function that returns data +// from the "deis" K8s namespace for RESTful consumption +func getK8sDeisNamespace(k k8s.RunningK8sData) *models.Namespace { + pods, err := k8s.GetPodsModels(k) + if err != nil { + log.Println("unable to get K8s pods data") + } + services, err := k8s.GetServicesModels(k) + if err != nil { + log.Println("unable to get K8s services data") + } + replicationControllers, err := k8s.GetReplicationControllersModels(k) + if err != nil { + log.Println("unable to get K8s RC data") + } + replicaSets, err := k8s.GetReplicaSetsModels(k) + if err != nil { + log.Println("unable to get K8s replicaSets data") + } + daemonSets, err := k8s.GetDaemonSetsModels(k) + if err != nil { + log.Println("unable to get K8s daemonSets data") + } + deployments, err := k8s.GetDeploymentsModels(k) + if err != nil { + log.Println("unable to get K8s deployments data") + } + events, err := k8s.GetEventsModels(k) + if err != nil { + log.Println("unable to get K8s events data") + } + return &models.Namespace{ + Name: config.Spec.DeisNamespace, + DaemonSets: daemonSets, + Deployments: deployments, + Events: events, + Pods: pods, + ReplicaSets: replicaSets, + ReplicationControllers: replicationControllers, + Services: services, + } +} + +// getK8sNodes is a helper function that returns K8s nodes data for RESTful consumption +func getK8sNodes(k k8s.RunningK8sData) []*models.K8sResource { + nodes, err := k8s.GetNodesModels(k) + if err != nil { + log.Println("unable to get K8s nodes data") + } + return nodes +} + // newestVersion is a temporary static implementation of a real "return newest version" function func newestVersion(v1 string, v2 string) string { return v1 diff --git a/data/data_test.go b/data/data_test.go index def2ee3..0211a2c 100644 --- a/data/data_test.go +++ b/data/data_test.go @@ -1,7 +1,6 @@ package data import ( - "encoding/json" "fmt" "testing" @@ -32,54 +31,6 @@ func (c *testClusterID) StoreInCache(cid string) { c.cache = cid } -// Creating a novel mock struct that fulfills the AvailableVersions interface -type testAvailableVersions struct{} - -func (a testAvailableVersions) Refresh(cluster models.Cluster) ([]models.ComponentVersion, error) { - data := getMockComponentVersions() - var componentVersions []models.ComponentVersion - _ = json.Unmarshal(data, &componentVersions) - return componentVersions, nil -} - -func (a testAvailableVersions) Store(c []models.ComponentVersion) { - return -} - -func (a testAvailableVersions) Cached() []models.ComponentVersion { - return nil -} - -// Creating another mock struct that fulfills the AvailableVersions interface -type shouldBypassAvailableVersions struct{} - -func (a shouldBypassAvailableVersions) Refresh(cluster models.Cluster) ([]models.ComponentVersion, error) { - var componentVersions []models.ComponentVersion - data := []byte(fmt.Sprintf(`[{ - "components": [ - { - "component": { - "name": "bypass me", - "description": "bypass me" - }, - "version": { - "version": "v2-bypass" - } - } - ] - }]`)) - _ = json.Unmarshal(data, &componentVersions) - return componentVersions, nil -} - -func (a shouldBypassAvailableVersions) Store(c []models.ComponentVersion) { - return -} - -func (a shouldBypassAvailableVersions) Cached() []models.ComponentVersion { - return nil -} - // Creating a novel mock struct that fulfills the InstalledData interface type mockInstalledComponents struct { } @@ -133,28 +84,12 @@ func TestGetID(t *testing.T) { assert.Equal(t, id, "something else", "cluster ID value") } -// Calls GetAvailableVersions twice, the first time we expect our passed-in struct w/ Refresh() method -// to be invoked, the 2nd time we expect to receive the same value back (cached in memory) -// and for the passed-in Refresh() method to be ignored -func TestGetAvailableVersions(t *testing.T) { - mock := getMockComponentVersions() - var mockVersions []models.ComponentVersion - assert.NoErr(t, json.Unmarshal(mock, &mockVersions)) - versions, err := GetAvailableVersions(testAvailableVersions{}, models.Cluster{}) - assert.NoErr(t, err) - assert.Equal(t, versions, mockVersions, "component versions data") - versions, err = GetAvailableVersions(shouldBypassAvailableVersions{}, models.Cluster{}) - assert.NoErr(t, err) - assert.Equal(t, versions, mockVersions, "component versions data") -} - func TestGetCluster(t *testing.T) { mockCluster := getMockCluster(t) cluster, err := GetCluster( mocks.InstalledMockData{}, &mocks.ClusterIDMockData{}, mocks.LatestMockData{}, - NewFakeKubeSecretGetterCreator(nil, nil), ) assert.NoErr(t, err) assert.Equal(t, cluster, mockCluster, "clusters") @@ -164,18 +99,18 @@ func TestGetDoctorInfo(t *testing.T) { mockCluster := getMockCluster(t) doctorInfo, err := GetDoctorInfo( mocks.InstalledMockData{}, + mocks.RunningK8sMockData{}, // TODO: add k8s mock data &mocks.ClusterIDMockData{}, mocks.LatestMockData{}, - NewFakeKubeSecretGetterCreator(nil, nil), ) assert.NoErr(t, err) - assert.Equal(t, *doctorInfo.Cluster, mockCluster, "clusters") + assert.Equal(t, *doctorInfo.Workflow, mockCluster, "clusters") } func TestAddUpdateData(t *testing.T) { mockCluster := getMockCluster(t) // AddUpdateData should add an "UpdateAvailable" field to any components whose versions are out-of-date - err := AddUpdateData(&mockCluster, mocks.LatestMockData{}, NewFakeKubeSecretGetterCreator(nil, nil)) + err := AddUpdateData(&mockCluster, mocks.LatestMockData{}) assert.NoErr(t, err) //TODO: when newestVersion is implemented, actually test for the addition of "UpdateAvailable" fields. // tracked in https://github.com/deis/workflow-manager/issues/52 diff --git a/data/installed_data.go b/data/installed_data.go index 9a2af83..0244808 100644 --- a/data/installed_data.go +++ b/data/installed_data.go @@ -3,7 +3,7 @@ package data import ( "encoding/json" - "github.com/arschles/kubeapp/api/rc" + "github.com/deis/workflow-manager/k8s" "github.com/deis/workflow-manager/pkg/swagger/models" ) @@ -15,17 +15,17 @@ type InstalledData interface { // InstalledDeisData fulfills the InstalledData interface type installedDeisData struct { - rcLister rc.Lister + k8sResources *k8s.ResourceInterfaceNamespaced } // NewInstalledDeisData returns a new InstalledDeisData using rcl as the rc.Lister implementation -func NewInstalledDeisData(rcl rc.Lister) InstalledData { - return &installedDeisData{rcLister: rcl} +func NewInstalledDeisData(ri *k8s.ResourceInterfaceNamespaced) InstalledData { + return &installedDeisData{k8sResources: ri} } // Get method for InstalledDeisData func (g *installedDeisData) Get() ([]byte, error) { - rcItems, err := getRCItems(g.rcLister) + rcItems, err := k8s.GetReplicationControllers(g.k8sResources.ReplicationControllers()) if err != nil { return nil, err } diff --git a/glide.lock b/glide.lock index bbe207b..31fe06e 100644 --- a/glide.lock +++ b/glide.lock @@ -1,16 +1,10 @@ -hash: 344acba1c0c3d637beff814c5d273de818c3ecd758f453fea85e085c3bd93701 -updated: 2016-05-24T14:55:13.473111277-04:00 +hash: b64e0a5c65cb4f9289e33a902292753e8e66922cf41e3fcd776507f2be156b08 +updated: 2016-07-19T18:06:10.791383535Z imports: - name: bitbucket.org/ww/goautoneg version: 75cd24fc2f2c - name: github.com/arschles/assert - version: 5c22e2eba944d89ddd5c81b2c4175e64ee828503 -- name: github.com/arschles/kubeapp - version: d970a2ec475267698e3cd6412b4204520b8d653d - subpackages: - - api - - api/rc - - api/secret + version: fc2da9844984ce5093111298174706e14d4c0c47 - name: github.com/arschles/testsrv version: 1ca51fb1a3b6e612411883cf1c9dbc58319b1d5b - name: github.com/asaskevich/govalidator @@ -26,6 +20,18 @@ imports: version: 3e6e67c4dcea3ac2f25fd4731abc0e1deaf36216 subpackages: - spew +- name: github.com/deis/kubeapp + version: d1fd2e1f9db4b8584edc540d523a85af9c51e71e + subpackages: + - api + - api/rc + - api/daemonset + - api/deployment + - api/node + - api/pod + - api/replicaset + - api/service + - api/secret - name: github.com/docker/docker version: 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d subpackages: @@ -48,8 +54,8 @@ imports: - name: github.com/go-swagger/go-swagger version: ff42df2bf231f6a12383b36332f8364254ea86d6 subpackages: - - client - httpkit/client + - client - strfmt - errors - httpkit @@ -85,9 +91,9 @@ imports: - name: github.com/google/gofuzz version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5 - name: github.com/gorilla/context - version: a8d44e7d8e4d532b6a27a02dd82abb31cc1b01bd + version: aed02d124ae4a0e94fea4541c8effd05bf0c8296 - name: github.com/gorilla/mux - version: 9c19ed558d5df4da88e2ade9c8940d742aef0e7e + version: d391bea3118c9fc17a88d62c9189bb791255e0ef - name: github.com/juju/ratelimit version: 77ed1c8a01217656d2080ad51981f6e99adaa177 - name: github.com/kelseyhightower/envconfig @@ -122,7 +128,7 @@ imports: - name: github.com/prometheus/procfs version: 490cc6eb5fa45bf8a8b7b73c8bc82a8160e8531d - name: github.com/satori/go.uuid - version: f9ab0dce87d815821e221626b772e3475a0d2749 + version: 0aa62d5ddceb50dbcb909d790b5345affd3669b6 - name: github.com/spf13/pflag version: 08b1a584251b5b62f458943640fc8ebd4d50aaa5 - name: github.com/ugorji/go @@ -142,7 +148,7 @@ imports: - name: gopkg.in/yaml.v2 version: d466437aa4adc35830964cffc5b5f262c63ddcb4 - name: k8s.io/kubernetes - version: 3d6adabd365ed5f81a2a3b843c63626c27e4034d + version: e7503fde8ec6b3911dc7e22cae2619dc5bcec351 subpackages: - client/unversioned - labels @@ -150,8 +156,9 @@ imports: - pkg - pkg/client/unversioned - pkg/api - - pkg/labels - pkg/api/errors + - pkg/apis/extensions + - pkg/labels - pkg/api/install - pkg/api/meta - pkg/api/unversioned @@ -162,7 +169,6 @@ imports: - pkg/apis/batch - pkg/apis/batch/install - pkg/apis/componentconfig/install - - pkg/apis/extensions - pkg/apis/extensions/install - pkg/apis/metrics/install - pkg/client/restclient @@ -182,8 +188,8 @@ imports: - pkg/util - pkg/util/intstr - pkg/util/rand - - pkg/util/validation - pkg/util/validation/field + - pkg/util/validation - pkg/api/v1 - pkg/apimachinery - pkg/util/errors diff --git a/glide.yaml b/glide.yaml index 32e9508..3b904e2 100644 --- a/glide.yaml +++ b/glide.yaml @@ -17,6 +17,6 @@ import: repo: https://github.com/belua/inf vcs: git - package: github.com/arschles/testsrv -- package: github.com/arschles/kubeapp +- package: github.com/deis/kubeapp subpackages: - api diff --git a/handlers/handlers.go b/handlers/handlers.go index 4dc9c7b..8286cfc 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -5,9 +5,9 @@ import ( "encoding/json" "net/http" - "github.com/arschles/kubeapp/api/rc" "github.com/deis/workflow-manager/config" "github.com/deis/workflow-manager/data" + "github.com/deis/workflow-manager/k8s" apiclient "github.com/deis/workflow-manager/pkg/swagger/client" "github.com/deis/workflow-manager/pkg/swagger/client/operations" "github.com/gorilla/mux" @@ -23,25 +23,23 @@ const ( // RegisterRoutes attaches handler functions to routes func RegisterRoutes( r *mux.Router, - secretGetterCreator data.KubeSecretGetterCreator, - rcLister rc.Lister, availableVersions data.AvailableVersions, + k8sResources *k8s.ResourceInterfaceNamespaced, ) *mux.Router { - clusterID := data.NewClusterIDFromPersistentStorage(secretGetterCreator) + clusterID := data.NewClusterIDFromPersistentStorage(k8sResources.Secrets()) r.Handle(componentsRoute, ComponentsHandler( - data.NewInstalledDeisData(rcLister), + data.NewInstalledDeisData(k8sResources), clusterID, - data.NewLatestReleasedComponent(secretGetterCreator, rcLister, availableVersions), - secretGetterCreator, + data.NewLatestReleasedComponent(k8sResources, availableVersions), )) r.Handle(idRoute, IDHandler(clusterID)) doctorAPIClient, _ := config.GetSwaggerClient(config.Spec.DoctorAPIURL) r.Handle(doctorRoute, DoctorHandler( - data.NewInstalledDeisData(rcLister), + data.NewInstalledDeisData(k8sResources), + k8s.NewRunningK8sData(k8sResources), clusterID, - data.NewLatestReleasedComponent(secretGetterCreator, rcLister, availableVersions), - secretGetterCreator, + data.NewLatestReleasedComponent(k8sResources, availableVersions), doctorAPIClient, )).Methods("POST") return r @@ -52,10 +50,9 @@ func ComponentsHandler( c data.InstalledData, i data.ClusterID, v data.AvailableComponentVersion, - secretGetterCreator data.KubeSecretGetterCreator, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cluster, err := data.GetCluster(c, i, v, secretGetterCreator) + cluster, err := data.GetCluster(c, i, v) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -68,14 +65,14 @@ func ComponentsHandler( // DoctorHandler route handler func DoctorHandler( - c data.InstalledData, + c data.InstalledData, // deis cluster + k k8s.RunningK8sData, // k8s cluster i data.ClusterID, v data.AvailableComponentVersion, - secretGetterCreator data.KubeSecretGetterCreator, apiClient *apiclient.WorkflowManager, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - doctor, err := data.GetDoctorInfo(c, i, v, secretGetterCreator) + doctor, err := data.GetDoctorInfo(c, k, i, v) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 2d129d0..d3d4a95 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -39,6 +39,49 @@ func (g mockInstalledComponents) Get() ([]byte, error) { }`, mockInstalledComponentName, mockInstalledComponentDescription, mockInstalledComponentVersion)), nil } +// Creating a novel mock struct that fulfills the data.RunningK8sData interface +type mockRunningK8sData struct{} + +func (g mockRunningK8sData) DaemonSets() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) Deployments() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) Events() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) Nodes() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) Pods() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) ReplicaSets() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) ReplicationControllers() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +func (g mockRunningK8sData) Services() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + const mockID = "faa31f63-d8dc-42e3-9568-405d20a3f755" // Creating a novel mock struct that fulfills the data.ClusterID interface @@ -81,7 +124,6 @@ func TestComponentsHandler(t *testing.T) { mockInstalledComponents{}, &mockClusterID{}, mockAvailableVersion{}, - data.NewFakeKubeSecretGetterCreator(nil, nil), ) resp, err := getTestHandlerResponse(componentsHandler) assert.NoErr(t, err) @@ -110,9 +152,9 @@ func TestDoctorHandler(t *testing.T) { apiClient, err := config.GetSwaggerClient(ts.URL) doctorHandler := DoctorHandler( mockInstalledComponents{}, + mockRunningK8sData{}, // TODO: mock k8s node data &mockClusterID{}, mockAvailableVersion{}, - data.NewFakeKubeSecretGetterCreator(nil, nil), apiClient, ) resp, err := getTestHandlerResponse(doctorHandler) diff --git a/jobs/jobs.go b/jobs/jobs.go index d620e0e..e5d55c6 100644 --- a/jobs/jobs.go +++ b/jobs/jobs.go @@ -4,9 +4,9 @@ import ( "log" "time" - "github.com/arschles/kubeapp/api/rc" "github.com/deis/workflow-manager/config" "github.com/deis/workflow-manager/data" + "github.com/deis/workflow-manager/k8s" apiclient "github.com/deis/workflow-manager/pkg/swagger/client" "github.com/deis/workflow-manager/pkg/swagger/client/operations" ) @@ -21,34 +21,31 @@ type Periodic interface { // SendVersions fulfills the Periodic interface type sendVersions struct { - secretGetterCreator data.KubeSecretGetterCreator - rcLister rc.Lister - apiClient *apiclient.WorkflowManager - availableVersions data.AvailableVersions - frequency time.Duration + k8sResources *k8s.ResourceInterfaceNamespaced + apiClient *apiclient.WorkflowManager + availableVersions data.AvailableVersions + frequency time.Duration } // NewSendVersionsPeriodic creates a new SendVersions using sgc and rcl as the the secret getter / creator and replication controller lister implementations (respectively) func NewSendVersionsPeriodic( apiClient *apiclient.WorkflowManager, - sgc data.KubeSecretGetterCreator, - rcl rc.Lister, + ri *k8s.ResourceInterfaceNamespaced, availableVersions data.AvailableVersions, frequency time.Duration, ) Periodic { return &sendVersions{ - secretGetterCreator: sgc, - rcLister: rcl, - apiClient: apiClient, - availableVersions: availableVersions, - frequency: frequency, + k8sResources: ri, + apiClient: apiClient, + availableVersions: availableVersions, + frequency: frequency, } } // Do is the Periodic interface implementation func (s sendVersions) Do() error { if config.Spec.CheckVersions { - err := sendVersionsImpl(s.apiClient, s.secretGetterCreator, s.rcLister, s.availableVersions) + err := sendVersionsImpl(s.apiClient, s.k8sResources, s.availableVersions) if err != nil { return err } @@ -66,14 +63,12 @@ type getLatestVersionData struct { installedData data.InstalledData clusterID data.ClusterID availableComponentVsn data.AvailableComponentVersion - sgc data.KubeSecretGetterCreator + k8sResources k8s.ResourceInterfaceNamespaced frequency time.Duration } // NewGetLatestVersionDataPeriodic creates a new periodic implementation that gets latest version data. It uses sgc and rcl as the secret getter/creator and replication controller lister implementations (respectively) func NewGetLatestVersionDataPeriodic( - sgc data.KubeSecretGetterCreator, - rcl rc.Lister, installedData data.InstalledData, clusterID data.ClusterID, availVsn data.AvailableVersions, @@ -86,14 +81,13 @@ func NewGetLatestVersionDataPeriodic( installedData: installedData, clusterID: clusterID, availableComponentVsn: availCompVsn, - sgc: sgc, - frequency: frequency, + frequency: frequency, } } // Do is the Periodic interface implementation func (u *getLatestVersionData) Do() error { - cluster, err := data.GetCluster(u.installedData, u.clusterID, u.availableComponentVsn, u.sgc) + cluster, err := data.GetCluster(u.installedData, u.clusterID, u.availableComponentVsn) if err != nil { return err } @@ -135,15 +129,13 @@ func DoPeriodic(pSlice []Periodic) chan<- struct{} { // sendVersions sends cluster version data func sendVersionsImpl( apiClient *apiclient.WorkflowManager, - secretGetterCreator data.KubeSecretGetterCreator, - rcLister rc.Lister, + k8sResources *k8s.ResourceInterfaceNamespaced, availableVersions data.AvailableVersions, ) error { cluster, err := data.GetCluster( - data.NewInstalledDeisData(rcLister), - data.NewClusterIDFromPersistentStorage(secretGetterCreator), - data.NewLatestReleasedComponent(secretGetterCreator, rcLister, availableVersions), - secretGetterCreator, + data.NewInstalledDeisData(k8sResources), + data.NewClusterIDFromPersistentStorage(k8sResources.Secrets()), + data.NewLatestReleasedComponent(k8sResources, availableVersions), ) if err != nil { log.Println("error getting installed components data") diff --git a/k8s/interfaces.go b/k8s/interfaces.go new file mode 100644 index 0000000..ee96ae4 --- /dev/null +++ b/k8s/interfaces.go @@ -0,0 +1,72 @@ +package k8s + +import kcl "k8s.io/kubernetes/pkg/client/unversioned" + +// ResourceInterface is an interface for k8s resources +type ResourceInterface interface { + kcl.DaemonSetsNamespacer + kcl.DeploymentsNamespacer + kcl.EventNamespacer + kcl.NodesInterface + kcl.PodsNamespacer + kcl.ReplicaSetsNamespacer + kcl.ReplicationControllersNamespacer + kcl.SecretsNamespacer + kcl.ServicesNamespacer +} + +// ResourceInterfaceNamespaced is a "union" of ResourceInterface+namespace +type ResourceInterfaceNamespaced struct { + ri ResourceInterface + namespace string +} + +// NewResourceInterfaceNamespaced constructs an instance of ResourceInterfaceNamespaced +func NewResourceInterfaceNamespaced(ri ResourceInterface, ns string) *ResourceInterfaceNamespaced { + return &ResourceInterfaceNamespaced{ri: ri, namespace: ns} +} + +// DaemonSets implementation +func (r *ResourceInterfaceNamespaced) DaemonSets() kcl.DaemonSetInterface { + return r.ri.DaemonSets(r.namespace) +} + +// Deployments implementation +func (r *ResourceInterfaceNamespaced) Deployments() kcl.DeploymentInterface { + return r.ri.Deployments(r.namespace) +} + +// Events implementation +func (r *ResourceInterfaceNamespaced) Events() kcl.EventInterface { + return r.ri.Events(r.namespace) +} + +// Nodes implementation +func (r *ResourceInterfaceNamespaced) Nodes() kcl.NodeInterface { + return r.ri.Nodes() +} + +// Pods implementation +func (r *ResourceInterfaceNamespaced) Pods() kcl.PodInterface { + return r.ri.Pods(r.namespace) +} + +// ReplicaSets implementation +func (r *ResourceInterfaceNamespaced) ReplicaSets() kcl.ReplicaSetInterface { + return r.ri.ReplicaSets(r.namespace) +} + +// ReplicationControllers implementation +func (r *ResourceInterfaceNamespaced) ReplicationControllers() kcl.ReplicationControllerInterface { + return r.ri.ReplicationControllers(r.namespace) +} + +// Services implementation +func (r *ResourceInterfaceNamespaced) Services() kcl.ServiceInterface { + return r.ri.Services(r.namespace) +} + +// Secrets implementation +func (r *ResourceInterfaceNamespaced) Secrets() kcl.SecretsInterface { + return r.ri.Secrets(r.namespace) +} diff --git a/k8s/k8s.go b/k8s/k8s.go new file mode 100644 index 0000000..61eb1c5 --- /dev/null +++ b/k8s/k8s.go @@ -0,0 +1,350 @@ +package k8s + +import ( + "github.com/deis/kubeapp/api/daemonset" + "github.com/deis/kubeapp/api/deployment" + "github.com/deis/kubeapp/api/event" + "github.com/deis/kubeapp/api/node" + "github.com/deis/kubeapp/api/pod" + "github.com/deis/kubeapp/api/rc" + "github.com/deis/kubeapp/api/replicaset" + "github.com/deis/kubeapp/api/service" + "github.com/deis/workflow-manager/pkg/swagger/models" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/labels" +) + +// RunningK8sData is an interface for representing installed K8s data RESTFully +type RunningK8sData interface { + // get DaemonSet model data for RESTful consumption + DaemonSets() ([]*models.K8sResource, error) + // get Deployment model data for RESTful consumption + Deployments() ([]*models.K8sResource, error) + // get Event model data for RESTful consumption + Events() ([]*models.K8sResource, error) + // get Node model data for RESTful consumption + Nodes() ([]*models.K8sResource, error) + // get Pod model data for RESTful consumption + Pods() ([]*models.K8sResource, error) + // get ReplicaSet model data for RESTful consumption + ReplicaSets() ([]*models.K8sResource, error) + // get ReplicationController model data for RESTful consumption + ReplicationControllers() ([]*models.K8sResource, error) + // get Service model data for RESTful consumption + Services() ([]*models.K8sResource, error) +} + +// runningK8sData fulfills the RunningK8sData interface +type runningK8sData struct { + daemonSetLister daemonset.Lister + deploymentLister deployment.Lister + eventLister event.Lister + nodeLister node.Lister + podLister pod.Lister + rcLister rc.Lister + replicaSetLister replicaset.Lister + serviceLister service.Lister +} + +// NewRunningK8sData returns a new runningK8sData using rcl as the rc.Lister implementation +func NewRunningK8sData(r *ResourceInterfaceNamespaced) RunningK8sData { + return &runningK8sData{daemonSetLister: r.DaemonSets(), deploymentLister: r.Deployments(), eventLister: r.Events(), + nodeLister: r.Nodes(), podLister: r.Pods(), rcLister: r.ReplicationControllers(), replicaSetLister: r.ReplicaSets(), serviceLister: r.Services()} +} + +// DaemonSets method for runningK8sData +func (rkd *runningK8sData) DaemonSets() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + ds, err := getDaemonSets(rkd.daemonSetLister) + if err != nil { + return ret, err + } + for _, d := range ds { + daemonSet := &models.K8sResource{ + Data: &d, + } + ret = append(ret, daemonSet) + } + return ret, nil +} + +// Deployments method for runningK8sData +func (rkd *runningK8sData) Deployments() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + ds, err := getDeployments(rkd.deploymentLister) + if err != nil { + return ret, err + } + for _, d := range ds { + dep := &models.K8sResource{ + Data: &d, + } + ret = append(ret, dep) + } + return ret, nil +} + +// Events method for runningK8sData +func (rkd *runningK8sData) Events() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + events, err := getEvents(rkd.eventLister) + if err != nil { + return ret, err + } + for _, e := range events { + event := &models.K8sResource{ + Data: &e, + } + ret = append(ret, event) + } + return ret, nil +} + +// Nodes method for runningK8sData +func (rkd *runningK8sData) Nodes() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + nodes, err := getNodes(rkd.nodeLister) + if err != nil { + return ret, err + } + for _, n := range nodes { + node := &models.K8sResource{ + Data: &n, + } + ret = append(ret, node) + } + return ret, nil +} + +// Pods method for runningK8sData +func (rkd *runningK8sData) Pods() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + pods, err := getPods(rkd.podLister) + if err != nil { + return ret, err + } + for _, p := range pods { + pod := &models.K8sResource{ + Data: &p, + } + ret = append(ret, pod) + } + return ret, nil +} + +// ReplicaSets method for runningK8sData +func (rkd *runningK8sData) ReplicaSets() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + rs, err := getReplicaSets(rkd.replicaSetLister) + if err != nil { + return ret, err + } + for _, r := range rs { + replicaSet := &models.K8sResource{ + Data: &r, + } + ret = append(ret, replicaSet) + } + return ret, nil +} + +// ReplicationControllers method for runningK8sData +func (rkd *runningK8sData) ReplicationControllers() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + rcs, err := GetReplicationControllers(rkd.rcLister) + if err != nil { + return ret, err + } + for _, rc := range rcs { + replicationController := &models.K8sResource{ + Data: &rc, + } + ret = append(ret, replicationController) + } + return ret, nil +} + +// Services method for runningK8sData +func (rkd *runningK8sData) Services() ([]*models.K8sResource, error) { + ret := []*models.K8sResource{} + services, err := getServices(rkd.serviceLister) + if err != nil { + return ret, err + } + for _, s := range services { + service := &models.K8sResource{ + Data: &s, + } + ret = append(ret, service) + } + return ret, nil +} + +// GetNodesModels gets k8s node model data for RESTful consumption +func GetNodesModels(k RunningK8sData) ([]*models.K8sResource, error) { + nodes, err := k.Nodes() + if err != nil { + return []*models.K8sResource{}, err + } + return nodes, nil +} + +// GetPodsModels gets k8s pod model data for RESTful consumption +func GetPodsModels(k RunningK8sData) ([]*models.K8sResource, error) { + pods, err := k.Pods() + if err != nil { + return []*models.K8sResource{}, err + } + return pods, nil +} + +// GetDeploymentsModels gets k8s deployment model data for RESTful consumption +func GetDeploymentsModels(k RunningK8sData) ([]*models.K8sResource, error) { + ds, err := k.Deployments() + if err != nil { + return []*models.K8sResource{}, err + } + return ds, nil +} + +// GetEventsModels gets k8s event model data for RESTful consumption +func GetEventsModels(k RunningK8sData) ([]*models.K8sResource, error) { + events, err := k.Events() + if err != nil { + return []*models.K8sResource{}, err + } + return events, nil +} + +// GetDaemonSetsModels gets k8s daemonSet model data for RESTful consumption +func GetDaemonSetsModels(k RunningK8sData) ([]*models.K8sResource, error) { + ds, err := k.DaemonSets() + if err != nil { + return []*models.K8sResource{}, err + } + return ds, nil +} + +// GetReplicaSetsModels gets k8s replicaSet model data for RESTful consumption +func GetReplicaSetsModels(k RunningK8sData) ([]*models.K8sResource, error) { + rs, err := k.ReplicaSets() + if err != nil { + return []*models.K8sResource{}, err + } + return rs, nil +} + +// GetReplicationControllersModels gets k8s rc model data for RESTful consumption +func GetReplicationControllersModels(k RunningK8sData) ([]*models.K8sResource, error) { + rcs, err := k.ReplicationControllers() + if err != nil { + return []*models.K8sResource{}, err + } + return rcs, nil +} + +// GetServicesModels gets k8s pod model data for RESTful consumption +func GetServicesModels(k RunningK8sData) ([]*models.K8sResource, error) { + services, err := k.Services() + if err != nil { + return []*models.K8sResource{}, err + } + return services, nil +} + +// GetReplicationControllers is a helper function that returns a slice of +// ReplicationController objects given a rc.Lister interface +func GetReplicationControllers(rcLister rc.Lister) ([]api.ReplicationController, error) { + rcs, err := rcLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []api.ReplicationController{}, err + } + return rcs.Items, nil +} + +// getNodes is a helper function that returns a slice of +// Node objects given a node.Lister interface +func getNodes(nodeLister node.Lister) ([]api.Node, error) { + nodes, err := nodeLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []api.Node{}, err + } + return nodes.Items, nil +} + +// getPods is a helper function that returns a slice of +// Pod objects given a pod.Lister interface +func getPods(podLister pod.Lister) ([]api.Pod, error) { + pods, err := podLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []api.Pod{}, err + } + return pods.Items, nil +} + +// getDaemonSets is a helper function that returns a slice of +// DaemonSet objects given a daemonset.Lister interface +func getDaemonSets(dsLister daemonset.Lister) ([]extensions.DaemonSet, error) { + daemonSets, err := dsLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []extensions.DaemonSet{}, err + } + return daemonSets.Items, nil +} + +// getDeployments is a helper function that returns a slice of +// Deployment objects given a deployment.Lister interface +func getDeployments(dLister deployment.Lister) ([]extensions.Deployment, error) { + deployments, err := dLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []extensions.Deployment{}, err + } + return deployments.Items, nil +} + +// getEvents is a helper function that returns a slice of +// Event objects given an event.Lister interface +func getEvents(eLister event.Lister) ([]api.Event, error) { + events, err := eLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []api.Event{}, err + } + return events.Items, nil +} + +// getReplicaSets is a helper function that returns a slice of +// ReplicaSet objects given a replicaset.Lister interface +func getReplicaSets(rsLister replicaset.Lister) ([]extensions.ReplicaSet, error) { + replicaSets, err := rsLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []extensions.ReplicaSet{}, err + } + return replicaSets.Items, nil +} + +// getServices is a helper function that returns a slice of +// Service objects given a service.Lister interface +func getServices(serviceLister service.Lister) ([]api.Service, error) { + services, err := serviceLister.List(api.ListOptions{ + LabelSelector: labels.Everything(), + }) + if err != nil { + return []api.Service{}, err + } + return services.Items, nil +} diff --git a/data/kube_secret_getter_creator.go b/k8s/kube_secret_getter_creator.go similarity index 93% rename from data/kube_secret_getter_creator.go rename to k8s/kube_secret_getter_creator.go index 936e09f..7e5d3a9 100644 --- a/data/kube_secret_getter_creator.go +++ b/k8s/kube_secret_getter_creator.go @@ -1,7 +1,7 @@ -package data +package k8s import ( - "github.com/arschles/kubeapp/api/secret" + "github.com/deis/kubeapp/api/secret" ) // KubeSecretGetterCreator is a composition of secret.Getter and secret.Creator. Please refer to the Godoc for those two interfaces (https://godoc.org/github.com/arschles/kubeapp/api/secret) diff --git a/mocks/mocks.go b/mocks/mocks.go index c4993bb..48b34d6 100644 --- a/mocks/mocks.go +++ b/mocks/mocks.go @@ -39,6 +39,57 @@ func (g InstalledMockData) Get() ([]byte, error) { return data, nil } +// RunningK8sMockData data struct +type RunningK8sMockData struct{} + +// DaemonSets method for RunningK8sMockData +func (k RunningK8sMockData) DaemonSets() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// Deployments method for RunningK8sMockData +func (k RunningK8sMockData) Deployments() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// Events method for RunningK8sMockData +func (k RunningK8sMockData) Events() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// Nodes method for RunningK8sMockData +func (k RunningK8sMockData) Nodes() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// Pods method for RunningK8sMockData +func (k RunningK8sMockData) Pods() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// ReplicaSets method for RunningK8sMockData +func (k RunningK8sMockData) ReplicaSets() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// ReplicationControllers method for RunningK8sMockData +func (k RunningK8sMockData) ReplicationControllers() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + +// Services method for RunningK8sMockData +func (k RunningK8sMockData) Services() ([]*models.K8sResource, error) { + // TODO: implement + return []*models.K8sResource{}, nil +} + // ClusterIDMockData mock data struct type ClusterIDMockData struct { cache string diff --git a/pkg/swagger/models/data.go b/pkg/swagger/models/data.go index f89c86e..2cec342 100644 --- a/pkg/swagger/models/data.go +++ b/pkg/swagger/models/data.go @@ -4,10 +4,11 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( - "github.com/go-swagger/go-swagger/errors" - "github.com/go-swagger/go-swagger/httpkit/validate" strfmt "github.com/go-swagger/go-swagger/strfmt" "github.com/go-swagger/go-swagger/swag" + + "github.com/go-swagger/go-swagger/errors" + "github.com/go-swagger/go-swagger/httpkit/validate" ) /*Data data diff --git a/pkg/swagger/models/doctor_info.go b/pkg/swagger/models/doctor_info.go index 5d1a766..384c35c 100644 --- a/pkg/swagger/models/doctor_info.go +++ b/pkg/swagger/models/doctor_info.go @@ -7,6 +7,7 @@ import ( strfmt "github.com/go-swagger/go-swagger/strfmt" "github.com/go-swagger/go-swagger/errors" + "github.com/go-swagger/go-swagger/httpkit/validate" ) /*DoctorInfo doctor info @@ -15,18 +16,40 @@ swagger:model doctorInfo */ type DoctorInfo struct { - /* cluster + /* namespaces Required: true */ - Cluster *Cluster `json:"cluster"` + Namespaces []*Namespace `json:"namespaces"` + + /* nodes + + Required: true + */ + Nodes []*K8sResource `json:"nodes"` + + /* workflow + + Required: true + */ + Workflow *Cluster `json:"workflow"` } // Validate validates this doctor info func (m *DoctorInfo) Validate(formats strfmt.Registry) error { var res []error - if err := m.validateCluster(formats); err != nil { + if err := m.validateNamespaces(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateNodes(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateWorkflow(formats); err != nil { // prop res = append(res, err) } @@ -37,11 +60,51 @@ func (m *DoctorInfo) Validate(formats strfmt.Registry) error { return nil } -func (m *DoctorInfo) validateCluster(formats strfmt.Registry) error { +func (m *DoctorInfo) validateNamespaces(formats strfmt.Registry) error { + + if err := validate.Required("namespaces", "body", m.Namespaces); err != nil { + return err + } + + for i := 0; i < len(m.Namespaces); i++ { + + if m.Namespaces[i] != nil { + + if err := m.Namespaces[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *DoctorInfo) validateNodes(formats strfmt.Registry) error { + + if err := validate.Required("nodes", "body", m.Nodes); err != nil { + return err + } + + for i := 0; i < len(m.Nodes); i++ { + + if m.Nodes[i] != nil { + + if err := m.Nodes[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *DoctorInfo) validateWorkflow(formats strfmt.Registry) error { - if m.Cluster != nil { + if m.Workflow != nil { - if err := m.Cluster.Validate(formats); err != nil { + if err := m.Workflow.Validate(formats); err != nil { return err } } diff --git a/pkg/swagger/models/k8s_resource.go b/pkg/swagger/models/k8s_resource.go new file mode 100644 index 0000000..8e34b02 --- /dev/null +++ b/pkg/swagger/models/k8s_resource.go @@ -0,0 +1,43 @@ +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + strfmt "github.com/go-swagger/go-swagger/strfmt" + + "github.com/go-swagger/go-swagger/errors" +) + +/*K8sResource k8s resource + +swagger:model k8sResource +*/ +type K8sResource struct { + + /* data + + Required: true + */ + Data interface{} `json:"data"` +} + +// Validate validates this k8s resource +func (m *K8sResource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateData(formats); err != nil { + // prop + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *K8sResource) validateData(formats strfmt.Registry) error { + + return nil +} diff --git a/pkg/swagger/models/namespace.go b/pkg/swagger/models/namespace.go new file mode 100644 index 0000000..92ff08f --- /dev/null +++ b/pkg/swagger/models/namespace.go @@ -0,0 +1,265 @@ +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + strfmt "github.com/go-swagger/go-swagger/strfmt" + + "github.com/go-swagger/go-swagger/errors" + "github.com/go-swagger/go-swagger/httpkit/validate" +) + +/*Namespace namespace + +swagger:model namespace +*/ +type Namespace struct { + + /* daemon sets + + Required: true + */ + DaemonSets []*K8sResource `json:"daemonSets"` + + /* deployments + + Required: true + */ + Deployments []*K8sResource `json:"deployments"` + + /* events + + Required: true + */ + Events []*K8sResource `json:"events"` + + /* name + + Required: true + */ + Name string `json:"name"` + + /* pods + + Required: true + */ + Pods []*K8sResource `json:"pods"` + + /* replica sets + + Required: true + */ + ReplicaSets []*K8sResource `json:"replicaSets"` + + /* replication controllers + + Required: true + */ + ReplicationControllers []*K8sResource `json:"replicationControllers"` + + /* services + + Required: true + */ + Services []*K8sResource `json:"services"` +} + +// Validate validates this namespace +func (m *Namespace) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateDaemonSets(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateDeployments(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateEvents(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateName(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validatePods(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateReplicaSets(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateReplicationControllers(formats); err != nil { + // prop + res = append(res, err) + } + + if err := m.validateServices(formats); err != nil { + // prop + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Namespace) validateDaemonSets(formats strfmt.Registry) error { + + if err := validate.Required("daemonSets", "body", m.DaemonSets); err != nil { + return err + } + + for i := 0; i < len(m.DaemonSets); i++ { + + if m.DaemonSets[i] != nil { + + if err := m.DaemonSets[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *Namespace) validateDeployments(formats strfmt.Registry) error { + + if err := validate.Required("deployments", "body", m.Deployments); err != nil { + return err + } + + for i := 0; i < len(m.Deployments); i++ { + + if m.Deployments[i] != nil { + + if err := m.Deployments[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *Namespace) validateEvents(formats strfmt.Registry) error { + + if err := validate.Required("events", "body", m.Events); err != nil { + return err + } + + for i := 0; i < len(m.Events); i++ { + + if m.Events[i] != nil { + + if err := m.Events[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *Namespace) validateName(formats strfmt.Registry) error { + + if err := validate.RequiredString("name", "body", string(m.Name)); err != nil { + return err + } + + return nil +} + +func (m *Namespace) validatePods(formats strfmt.Registry) error { + + if err := validate.Required("pods", "body", m.Pods); err != nil { + return err + } + + for i := 0; i < len(m.Pods); i++ { + + if m.Pods[i] != nil { + + if err := m.Pods[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *Namespace) validateReplicaSets(formats strfmt.Registry) error { + + if err := validate.Required("replicaSets", "body", m.ReplicaSets); err != nil { + return err + } + + for i := 0; i < len(m.ReplicaSets); i++ { + + if m.ReplicaSets[i] != nil { + + if err := m.ReplicaSets[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *Namespace) validateReplicationControllers(formats strfmt.Registry) error { + + if err := validate.Required("replicationControllers", "body", m.ReplicationControllers); err != nil { + return err + } + + for i := 0; i < len(m.ReplicationControllers); i++ { + + if m.ReplicationControllers[i] != nil { + + if err := m.ReplicationControllers[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *Namespace) validateServices(formats strfmt.Registry) error { + + if err := validate.Required("services", "body", m.Services); err != nil { + return err + } + + for i := 0; i < len(m.Services); i++ { + + if m.Services[i] != nil { + + if err := m.Services[i].Validate(formats); err != nil { + return err + } + } + + } + + return nil +} diff --git a/pkg/swagger/models/version.go b/pkg/swagger/models/version.go index af8581d..94ecd04 100644 --- a/pkg/swagger/models/version.go +++ b/pkg/swagger/models/version.go @@ -4,10 +4,11 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( - "github.com/go-swagger/go-swagger/errors" - "github.com/go-swagger/go-swagger/httpkit/validate" strfmt "github.com/go-swagger/go-swagger/strfmt" "github.com/go-swagger/go-swagger/swag" + + "github.com/go-swagger/go-swagger/errors" + "github.com/go-swagger/go-swagger/httpkit/validate" ) /*Version version From 6ba6ec7f893445b48598d67cc4b2773280dee4dd Mon Sep 17 00:00:00 2001 From: Jack Francis Date: Fri, 29 Jul 2016 15:44:49 -0700 Subject: [PATCH 2/4] fix(misc): err responses, code cleanup, light optimizations --- data/available_versions_test.go | 10 ++++-- data/data.go | 21 ++++++------ handlers/handlers.go | 24 +++++++------- jobs/jobs.go | 6 ++-- k8s/k8s.go | 58 +++++++++++++++++++-------------- 5 files changed, 66 insertions(+), 53 deletions(-) diff --git a/data/available_versions_test.go b/data/available_versions_test.go index 9705771..daa1301 100644 --- a/data/available_versions_test.go +++ b/data/available_versions_test.go @@ -20,7 +20,10 @@ type testAvailableVersions struct{} func (a testAvailableVersions) Refresh(cluster models.Cluster) ([]models.ComponentVersion, error) { data := getMockComponentVersions() var componentVersions []models.ComponentVersion - _ = json.Unmarshal(data, &componentVersions) + err := json.Unmarshal(data, &componentVersions) + if err != nil { + return nil, err + } return componentVersions, nil } @@ -50,7 +53,10 @@ func (a shouldBypassAvailableVersions) Refresh(cluster models.Cluster) ([]models } ] }]`)) - _ = json.Unmarshal(data, &componentVersions) + err := json.Unmarshal(data, &componentVersions) + if err != nil { + return nil, err + } return componentVersions, nil } diff --git a/data/data.go b/data/data.go index 8375a3e..e9511c2 100644 --- a/data/data.go +++ b/data/data.go @@ -30,7 +30,7 @@ func GetCluster( } err = AddUpdateData(&cluster, v) if err != nil { - log.Println("unable to decorate cluster data with available updates data") + log.Printf("unable to decorate cluster data with available updates data: %#v\n", err) } // Get the cluster ID id, err := GetID(i) @@ -145,11 +145,10 @@ func GetDoctorInfo( ) (models.DoctorInfo, error) { cluster, err := GetCluster(c, i, v) if err != nil { - log.Println("unable to get workflow cluster data") + return models.DoctorInfo{}, err } nodes := getK8sNodes(k) - var namespaces []*models.Namespace - namespaces = append(namespaces, getK8sDeisNamespace(k)) + namespaces := []*models.Namespace{getK8sDeisNamespace(k)} doctor := models.DoctorInfo{ Workflow: &cluster, Nodes: nodes, @@ -163,31 +162,31 @@ func GetDoctorInfo( func getK8sDeisNamespace(k k8s.RunningK8sData) *models.Namespace { pods, err := k8s.GetPodsModels(k) if err != nil { - log.Println("unable to get K8s pods data") + log.Printf("unable to get K8s pods data: %#v\n", err) } services, err := k8s.GetServicesModels(k) if err != nil { - log.Println("unable to get K8s services data") + log.Printf("unable to get K8s services data: %#v\n", err) } replicationControllers, err := k8s.GetReplicationControllersModels(k) if err != nil { - log.Println("unable to get K8s RC data") + log.Printf("unable to get K8s RC data: %#v\n", err) } replicaSets, err := k8s.GetReplicaSetsModels(k) if err != nil { - log.Println("unable to get K8s replicaSets data") + log.Printf("unable to get K8s replicaSets data: %#v\n", err) } daemonSets, err := k8s.GetDaemonSetsModels(k) if err != nil { - log.Println("unable to get K8s daemonSets data") + log.Printf("unable to get K8s daemonSets data: %#v\n", err) } deployments, err := k8s.GetDeploymentsModels(k) if err != nil { - log.Println("unable to get K8s deployments data") + log.Printf("unable to get K8s deployments data: %#v\n", err) } events, err := k8s.GetEventsModels(k) if err != nil { - log.Println("unable to get K8s events data") + log.Printf("unable to get K8s events data: %#v\n", err) } return &models.Namespace{ Name: config.Spec.DeisNamespace, diff --git a/handlers/handlers.go b/handlers/handlers.go index 8286cfc..64ff1af 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -23,7 +23,7 @@ const ( // RegisterRoutes attaches handler functions to routes func RegisterRoutes( r *mux.Router, - availableVersions data.AvailableVersions, + availVers data.AvailableVersions, k8sResources *k8s.ResourceInterfaceNamespaced, ) *mux.Router { @@ -31,7 +31,7 @@ func RegisterRoutes( r.Handle(componentsRoute, ComponentsHandler( data.NewInstalledDeisData(k8sResources), clusterID, - data.NewLatestReleasedComponent(k8sResources, availableVersions), + data.NewLatestReleasedComponent(k8sResources, availVers), )) r.Handle(idRoute, IDHandler(clusterID)) doctorAPIClient, _ := config.GetSwaggerClient(config.Spec.DoctorAPIURL) @@ -39,7 +39,7 @@ func RegisterRoutes( data.NewInstalledDeisData(k8sResources), k8s.NewRunningK8sData(k8sResources), clusterID, - data.NewLatestReleasedComponent(k8sResources, availableVersions), + data.NewLatestReleasedComponent(k8sResources, availVers), doctorAPIClient, )).Methods("POST") return r @@ -47,12 +47,12 @@ func RegisterRoutes( // ComponentsHandler route handler func ComponentsHandler( - c data.InstalledData, - i data.ClusterID, - v data.AvailableComponentVersion, + workflow data.InstalledData, + clusterID data.ClusterID, + availVers data.AvailableComponentVersion, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cluster, err := data.GetCluster(c, i, v) + cluster, err := data.GetCluster(workflow, clusterID, availVers) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -65,14 +65,14 @@ func ComponentsHandler( // DoctorHandler route handler func DoctorHandler( - c data.InstalledData, // deis cluster - k k8s.RunningK8sData, // k8s cluster - i data.ClusterID, - v data.AvailableComponentVersion, + workflow data.InstalledData, + k8sData k8s.RunningK8sData, + clusterID data.ClusterID, + availVers data.AvailableComponentVersion, apiClient *apiclient.WorkflowManager, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - doctor, err := data.GetDoctorInfo(c, k, i, v) + doctor, err := data.GetDoctorInfo(workflow, k8sData, clusterID, availVers) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/jobs/jobs.go b/jobs/jobs.go index e5d55c6..82400d4 100644 --- a/jobs/jobs.go +++ b/jobs/jobs.go @@ -21,7 +21,7 @@ type Periodic interface { // SendVersions fulfills the Periodic interface type sendVersions struct { - k8sResources *k8s.ResourceInterfaceNamespaced + k8sResources *k8s.ResourceInterfaceNamespaced apiClient *apiclient.WorkflowManager availableVersions data.AvailableVersions frequency time.Duration @@ -35,7 +35,7 @@ func NewSendVersionsPeriodic( frequency time.Duration, ) Periodic { return &sendVersions{ - k8sResources: ri, + k8sResources: ri, apiClient: apiClient, availableVersions: availableVersions, frequency: frequency, @@ -63,7 +63,7 @@ type getLatestVersionData struct { installedData data.InstalledData clusterID data.ClusterID availableComponentVsn data.AvailableComponentVersion - k8sResources k8s.ResourceInterfaceNamespaced + k8sResources k8s.ResourceInterfaceNamespaced frequency time.Duration } diff --git a/k8s/k8s.go b/k8s/k8s.go index 61eb1c5..6d17ce4 100644 --- a/k8s/k8s.go +++ b/k8s/k8s.go @@ -49,17 +49,25 @@ type runningK8sData struct { // NewRunningK8sData returns a new runningK8sData using rcl as the rc.Lister implementation func NewRunningK8sData(r *ResourceInterfaceNamespaced) RunningK8sData { - return &runningK8sData{daemonSetLister: r.DaemonSets(), deploymentLister: r.Deployments(), eventLister: r.Events(), - nodeLister: r.Nodes(), podLister: r.Pods(), rcLister: r.ReplicationControllers(), replicaSetLister: r.ReplicaSets(), serviceLister: r.Services()} + return &runningK8sData{ + daemonSetLister: r.DaemonSets(), + deploymentLister: r.Deployments(), + eventLister: r.Events(), + nodeLister: r.Nodes(), + podLister: r.Pods(), + rcLister: r.ReplicationControllers(), + replicaSetLister: r.ReplicaSets(), + serviceLister: r.Services(), + } } // DaemonSets method for runningK8sData func (rkd *runningK8sData) DaemonSets() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} ds, err := getDaemonSets(rkd.daemonSetLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(ds)) for _, d := range ds { daemonSet := &models.K8sResource{ Data: &d, @@ -71,11 +79,11 @@ func (rkd *runningK8sData) DaemonSets() ([]*models.K8sResource, error) { // Deployments method for runningK8sData func (rkd *runningK8sData) Deployments() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} ds, err := getDeployments(rkd.deploymentLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(ds)) for _, d := range ds { dep := &models.K8sResource{ Data: &d, @@ -87,11 +95,11 @@ func (rkd *runningK8sData) Deployments() ([]*models.K8sResource, error) { // Events method for runningK8sData func (rkd *runningK8sData) Events() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} events, err := getEvents(rkd.eventLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(events)) for _, e := range events { event := &models.K8sResource{ Data: &e, @@ -103,11 +111,11 @@ func (rkd *runningK8sData) Events() ([]*models.K8sResource, error) { // Nodes method for runningK8sData func (rkd *runningK8sData) Nodes() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} nodes, err := getNodes(rkd.nodeLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(nodes)) for _, n := range nodes { node := &models.K8sResource{ Data: &n, @@ -119,11 +127,11 @@ func (rkd *runningK8sData) Nodes() ([]*models.K8sResource, error) { // Pods method for runningK8sData func (rkd *runningK8sData) Pods() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} pods, err := getPods(rkd.podLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(pods)) for _, p := range pods { pod := &models.K8sResource{ Data: &p, @@ -135,11 +143,11 @@ func (rkd *runningK8sData) Pods() ([]*models.K8sResource, error) { // ReplicaSets method for runningK8sData func (rkd *runningK8sData) ReplicaSets() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} rs, err := getReplicaSets(rkd.replicaSetLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(rs)) for _, r := range rs { replicaSet := &models.K8sResource{ Data: &r, @@ -151,11 +159,11 @@ func (rkd *runningK8sData) ReplicaSets() ([]*models.K8sResource, error) { // ReplicationControllers method for runningK8sData func (rkd *runningK8sData) ReplicationControllers() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} rcs, err := GetReplicationControllers(rkd.rcLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(rcs)) for _, rc := range rcs { replicationController := &models.K8sResource{ Data: &rc, @@ -167,11 +175,11 @@ func (rkd *runningK8sData) ReplicationControllers() ([]*models.K8sResource, erro // Services method for runningK8sData func (rkd *runningK8sData) Services() ([]*models.K8sResource, error) { - ret := []*models.K8sResource{} services, err := getServices(rkd.serviceLister) if err != nil { - return ret, err + return nil, err } + ret := make([]*models.K8sResource, len(services)) for _, s := range services { service := &models.K8sResource{ Data: &s, @@ -185,7 +193,7 @@ func (rkd *runningK8sData) Services() ([]*models.K8sResource, error) { func GetNodesModels(k RunningK8sData) ([]*models.K8sResource, error) { nodes, err := k.Nodes() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return nodes, nil } @@ -194,7 +202,7 @@ func GetNodesModels(k RunningK8sData) ([]*models.K8sResource, error) { func GetPodsModels(k RunningK8sData) ([]*models.K8sResource, error) { pods, err := k.Pods() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return pods, nil } @@ -203,7 +211,7 @@ func GetPodsModels(k RunningK8sData) ([]*models.K8sResource, error) { func GetDeploymentsModels(k RunningK8sData) ([]*models.K8sResource, error) { ds, err := k.Deployments() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return ds, nil } @@ -212,7 +220,7 @@ func GetDeploymentsModels(k RunningK8sData) ([]*models.K8sResource, error) { func GetEventsModels(k RunningK8sData) ([]*models.K8sResource, error) { events, err := k.Events() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return events, nil } @@ -221,7 +229,7 @@ func GetEventsModels(k RunningK8sData) ([]*models.K8sResource, error) { func GetDaemonSetsModels(k RunningK8sData) ([]*models.K8sResource, error) { ds, err := k.DaemonSets() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return ds, nil } @@ -230,7 +238,7 @@ func GetDaemonSetsModels(k RunningK8sData) ([]*models.K8sResource, error) { func GetReplicaSetsModels(k RunningK8sData) ([]*models.K8sResource, error) { rs, err := k.ReplicaSets() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return rs, nil } @@ -239,7 +247,7 @@ func GetReplicaSetsModels(k RunningK8sData) ([]*models.K8sResource, error) { func GetReplicationControllersModels(k RunningK8sData) ([]*models.K8sResource, error) { rcs, err := k.ReplicationControllers() if err != nil { - return []*models.K8sResource{}, err + return nil, err } return rcs, nil } From 69efcf43ca0903da0f3b506230170441b64877d6 Mon Sep 17 00:00:00 2001 From: Jack Francis Date: Tue, 2 Aug 2016 09:57:43 -0700 Subject: [PATCH 3/4] chore(cleanup): err response, enumeration, log optimizations --- data/available_versions_test.go | 6 ++---- data/data.go | 22 ++++++++++------------ k8s/k8s.go | 32 ++++++++++++++++---------------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/data/available_versions_test.go b/data/available_versions_test.go index daa1301..a55deb4 100644 --- a/data/available_versions_test.go +++ b/data/available_versions_test.go @@ -20,8 +20,7 @@ type testAvailableVersions struct{} func (a testAvailableVersions) Refresh(cluster models.Cluster) ([]models.ComponentVersion, error) { data := getMockComponentVersions() var componentVersions []models.ComponentVersion - err := json.Unmarshal(data, &componentVersions) - if err != nil { + if err := json.Unmarshal(data, &componentVersions); err != nil { return nil, err } return componentVersions, nil @@ -53,8 +52,7 @@ func (a shouldBypassAvailableVersions) Refresh(cluster models.Cluster) ([]models } ] }]`)) - err := json.Unmarshal(data, &componentVersions) - if err != nil { + if err := json.Unmarshal(data, &componentVersions); err != nil { return nil, err } return componentVersions, nil diff --git a/data/data.go b/data/data.go index e9511c2..1402eb2 100644 --- a/data/data.go +++ b/data/data.go @@ -28,9 +28,8 @@ func GetCluster( if err != nil { return models.Cluster{}, err } - err = AddUpdateData(&cluster, v) - if err != nil { - log.Printf("unable to decorate cluster data with available updates data: %#v\n", err) + if err = AddUpdateData(&cluster, v); err != nil { + log.Printf("unable to decorate cluster data with available updates data: %#v", err) } // Get the cluster ID id, err := GetID(i) @@ -115,8 +114,7 @@ func GetLatestVersion( // to a Cluster type func ParseJSONCluster(rawJSON []byte) (models.Cluster, error) { var cluster models.Cluster - err := json.Unmarshal(rawJSON, &cluster) - if err != nil { + if err := json.Unmarshal(rawJSON, &cluster); err != nil { return models.Cluster{}, err } return cluster, nil @@ -162,31 +160,31 @@ func GetDoctorInfo( func getK8sDeisNamespace(k k8s.RunningK8sData) *models.Namespace { pods, err := k8s.GetPodsModels(k) if err != nil { - log.Printf("unable to get K8s pods data: %#v\n", err) + log.Printf("unable to get K8s pods data: %#v", err) } services, err := k8s.GetServicesModels(k) if err != nil { - log.Printf("unable to get K8s services data: %#v\n", err) + log.Printf("unable to get K8s services data: %#v", err) } replicationControllers, err := k8s.GetReplicationControllersModels(k) if err != nil { - log.Printf("unable to get K8s RC data: %#v\n", err) + log.Printf("unable to get K8s RC data: %#v", err) } replicaSets, err := k8s.GetReplicaSetsModels(k) if err != nil { - log.Printf("unable to get K8s replicaSets data: %#v\n", err) + log.Printf("unable to get K8s replicaSets data: %#v", err) } daemonSets, err := k8s.GetDaemonSetsModels(k) if err != nil { - log.Printf("unable to get K8s daemonSets data: %#v\n", err) + log.Printf("unable to get K8s daemonSets data: %#v", err) } deployments, err := k8s.GetDeploymentsModels(k) if err != nil { - log.Printf("unable to get K8s deployments data: %#v\n", err) + log.Printf("unable to get K8s deployments data: %#v", err) } events, err := k8s.GetEventsModels(k) if err != nil { - log.Printf("unable to get K8s events data: %#v\n", err) + log.Printf("unable to get K8s events data: %#v", err) } return &models.Namespace{ Name: config.Spec.DeisNamespace, diff --git a/k8s/k8s.go b/k8s/k8s.go index 6d17ce4..2f67420 100644 --- a/k8s/k8s.go +++ b/k8s/k8s.go @@ -68,11 +68,11 @@ func (rkd *runningK8sData) DaemonSets() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(ds)) - for _, d := range ds { + for i, d := range ds { daemonSet := &models.K8sResource{ Data: &d, } - ret = append(ret, daemonSet) + ret[i] = daemonSet } return ret, nil } @@ -84,11 +84,11 @@ func (rkd *runningK8sData) Deployments() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(ds)) - for _, d := range ds { + for i, d := range ds { dep := &models.K8sResource{ Data: &d, } - ret = append(ret, dep) + ret[i] = dep } return ret, nil } @@ -100,11 +100,11 @@ func (rkd *runningK8sData) Events() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(events)) - for _, e := range events { + for i, e := range events { event := &models.K8sResource{ Data: &e, } - ret = append(ret, event) + ret[i] = event } return ret, nil } @@ -116,11 +116,11 @@ func (rkd *runningK8sData) Nodes() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(nodes)) - for _, n := range nodes { + for i, n := range nodes { node := &models.K8sResource{ Data: &n, } - ret = append(ret, node) + ret[i] = node } return ret, nil } @@ -132,11 +132,11 @@ func (rkd *runningK8sData) Pods() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(pods)) - for _, p := range pods { + for i, p := range pods { pod := &models.K8sResource{ Data: &p, } - ret = append(ret, pod) + ret[i] = pod } return ret, nil } @@ -148,11 +148,11 @@ func (rkd *runningK8sData) ReplicaSets() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(rs)) - for _, r := range rs { + for i, r := range rs { replicaSet := &models.K8sResource{ Data: &r, } - ret = append(ret, replicaSet) + ret[i] = replicaSet } return ret, nil } @@ -164,11 +164,11 @@ func (rkd *runningK8sData) ReplicationControllers() ([]*models.K8sResource, erro return nil, err } ret := make([]*models.K8sResource, len(rcs)) - for _, rc := range rcs { + for i, rc := range rcs { replicationController := &models.K8sResource{ Data: &rc, } - ret = append(ret, replicationController) + ret[i] = replicationController } return ret, nil } @@ -180,11 +180,11 @@ func (rkd *runningK8sData) Services() ([]*models.K8sResource, error) { return nil, err } ret := make([]*models.K8sResource, len(services)) - for _, s := range services { + for i, s := range services { service := &models.K8sResource{ Data: &s, } - ret = append(ret, service) + ret[i] = service } return ret, nil } From 73bd54ffe50c0b633a72959a1b8950bf2cf5cc19 Mon Sep 17 00:00:00 2001 From: Jack Francis Date: Tue, 2 Aug 2016 10:31:40 -0700 Subject: [PATCH 4/4] chore(err): `if err :=` is preferred over `if err =` --- data/data.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/data.go b/data/data.go index 1402eb2..9159238 100644 --- a/data/data.go +++ b/data/data.go @@ -28,7 +28,7 @@ func GetCluster( if err != nil { return models.Cluster{}, err } - if err = AddUpdateData(&cluster, v); err != nil { + if err := AddUpdateData(&cluster, v); err != nil { log.Printf("unable to decorate cluster data with available updates data: %#v", err) } // Get the cluster ID