Skip to content

Commit

Permalink
listClusters in golang
Browse files Browse the repository at this point in the history
  • Loading branch information
laverya committed Aug 21, 2020
1 parent 5a6baa2 commit f89042c
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 241 deletions.
3 changes: 3 additions & 0 deletions kotsadm/pkg/apiserver/server.go
Expand Up @@ -177,6 +177,9 @@ func Start() {
r.Path("/api/v1/gitops/app/{appId}/cluster/{clusterId}/initconnection").Methods("OPTIONS", "POST").HandlerFunc(handlers.InitGitOpsConnection)
r.Path("/api/v1/gitops/reset").Methods("OPTIONS", "POST").HandlerFunc(handlers.ResetGitOps)

// Clusters
r.Path("/api/v1/clusters/list").Methods("OPTIONS", "GET").HandlerFunc(handlers.GetClusters)

// to avoid confusion, we don't serve this in the dev env...
if os.Getenv("DISABLE_SPA_SERVING") != "1" {
spa := handlers.SPAHandler{StaticPath: filepath.Join("web", "dist"), IndexPath: "index.html"}
Expand Down
45 changes: 45 additions & 0 deletions kotsadm/pkg/handlers/clusters.go
@@ -0,0 +1,45 @@
package handlers

import (
"net/http"

"github.com/replicatedhq/kots/kotsadm/pkg/logger"
"github.com/replicatedhq/kots/kotsadm/pkg/store"
)

type GetClustersResponse struct {
ID string `json:"id"`
Name string `json:"name"`
}

func GetClusters(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "content-type, origin, accept, authorization")

if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}

if err := requireValidSession(w, r); err != nil {
logger.Error(err)
return
}

clusters, err := store.GetStore().ListClusters()
if err != nil {
logger.Error(err)
w.WriteHeader(500)
return
}

resp := []GetClustersResponse{}
for idx, val := range clusters {
resp = append(resp, GetClustersResponse{
ID: idx,
Name: val,
})
}

JSON(w, 200, resp)
}
17 changes: 3 additions & 14 deletions kotsadm/pkg/store/s3pg/app_store.go
Expand Up @@ -20,23 +20,12 @@ import (
func (s S3PGStore) AddAppToAllDownstreams(appID string) error {
db := persistence.MustGetPGSession()

query := `select id, title from cluster`
rows, err := db.Query(query)
clusterIDs, err := s.ListClusters()
if err != nil {
return errors.Wrap(err, "failed to query clusters")
}
defer rows.Close()
clusterIDs := map[string]string{}
for rows.Next() {
clusterID := ""
name := ""
if err := rows.Scan(&clusterID, &name); err != nil {
return errors.Wrap(err, "failed to scan row")
}
clusterIDs[clusterID] = name
return errors.Wrap(err, "failed to list clusters")
}
for clusterID, name := range clusterIDs {
query = `insert into app_downstream (app_id, cluster_id, downstream_name) values ($1, $2, $3)`
query := `insert into app_downstream (app_id, cluster_id, downstream_name) values ($1, $2, $3)`
_, err = db.Exec(query, appID, clusterID, name)
if err != nil {
return errors.Wrap(err, "failed to create app downstream")
Expand Down
28 changes: 28 additions & 0 deletions kotsadm/pkg/store/s3pg/cluster_store.go
@@ -0,0 +1,28 @@
package s3pg

import (
"github.com/pkg/errors"
"github.com/replicatedhq/kots/kotsadm/pkg/persistence"
)

func (s S3PGStore) ListClusters() (map[string]string, error) {
db := persistence.MustGetPGSession()

query := `select id, title from cluster`
rows, err := db.Query(query)
if err != nil {
return nil, errors.Wrap(err, "failed to query clusters")
}
defer rows.Close()
clusterIDs := map[string]string{}
for rows.Next() {
clusterID := ""
name := ""
if err := rows.Scan(&clusterID, &name); err != nil {
return nil, errors.Wrap(err, "failed to scan row")
}
clusterIDs[clusterID] = name
}

return clusterIDs, nil
}
5 changes: 5 additions & 0 deletions kotsadm/pkg/store/store_interface.go
Expand Up @@ -25,6 +25,7 @@ type KOTSStore interface {
AppStatusStore
AppStore
LicenseStore
ClusterStore
}

type RegistryStore interface {
Expand Down Expand Up @@ -99,3 +100,7 @@ type AppStore interface {
type LicenseStore interface {
GetLicenseForApp(string) (*kotsv1beta1.License, error)
}

type ClusterStore interface {
ListClusters() (map[string]string, error)
}
91 changes: 1 addition & 90 deletions kotsadm/web/pacts/kotsadm-web-kotsadm-api.json
Expand Up @@ -6,95 +6,6 @@
"name": "kotsadm-api"
},
"interactions": [
{
"description": "a query to list clusters for solo account",
"request": {
"method": "POST",
"path": "/graphql",
"headers": {
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NDYzMDQ0MDAwMDAsInRva2VuIjoibm90LWNoZWNrZWQiLCJzZXNzaW9uSWQiOiJzb2xvLWFjY291bnQtc2Vzc2lvbi0xIn0.pC3xMQDD5zseVcOVzypZkC9ZyngBoT_nLymZTbJTHdA",
"Content-Type": "application/json"
},
"body": {
"operationName": "listClusters",
"query": "\n query listClusters {\n listClusters {\n id\n title\n slug\n createdOn\n lastUpdated\n shipOpsRef {\n token\n }\n totalApplicationCount\n }\n }\n",
"variables": {
}
},
"matchingRules": {
"$.body.query": {
"match": "regex",
"regex": "\\s*query\\s*listClusters\\s*\\{\\s*listClusters\\s*\\{\\s*id\\s*title\\s*slug\\s*createdOn\\s*lastUpdated\\s*shipOpsRef\\s*\\{\\s*token\\s*\\}\\s*totalApplicationCount\\s*\\}\\s*\\}\\s*"
}
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"data": {
"listClusters": [
{
"id": "solo-account-cluster-1",
"title": "Solo Cluster",
"slug": "solo-cluster",
"totalApplicationCount": 1,
"createdOn": "2019-04-10 12:34:56.789",
"lastUpdated": "2019-04-11 01:23:45.567",
"shipOpsRef": {
"token": "solo-account-cluster-token"
}
},
{
"id": "solo-account-cluster-2",
"title": "Solo GitHub Cluster",
"slug": "solo-cluster-2",
"totalApplicationCount": 0,
"createdOn": "2019-04-10 12:34:56.789",
"lastUpdated": "2019-04-11 01:23:45.567",
"shipOpsRef": null
},
{
"id": "l9cpydvcf30ekf25pmokwn6qlnxscrci",
"title": "this-cluster",
"slug": "this-cluster",
"createdOn": "Wed Jan 22 2020 00:34:12 GMT+0000 (Coordinated Universal Time)",
"lastUpdated": null,
"shipOpsRef": {
"token": "g7yoarinjpaft3si5z1h5de1uam443bb"
},
"totalApplicationCount": 0
}
]
}
},
"matchingRules": {
"$.body.data.listClusters[0].createdOn": {
"match": "type"
},
"$.body.data.listClusters[0].lastUpdated": {
"match": "type"
},
"$.body.data.listClusters[1].createdOn": {
"match": "type"
},
"$.body.data.listClusters[1].lastUpdated": {
"match": "type"
},
"$.body.data.listClusters[2].id": {
"match": "type"
},
"$.body.data.listClusters[2].createdOn": {
"match": "type"
},
"$.body.data.listClusters[2].shipOpsRef.token": {
"match": "type"
}
}
}
},
{
"description": "A query to get a kots app",
"request": {
Expand Down Expand Up @@ -458,4 +369,4 @@
"version": "2.0.0"
}
}
}
}
43 changes: 24 additions & 19 deletions kotsadm/web/src/components/clusters/GitOps.jsx
Expand Up @@ -4,8 +4,7 @@ import Helmet from "react-helmet";
import { graphql, compose, withApollo } from "react-apollo";
import { withRouter } from "react-router-dom";
import GitOpsDeploymentManager from "../gitops/GitOpsDeploymentManager";
import Loader from "../shared/Loader";
import { listClusters } from "../../queries/ClusterQueries";
import { Utilities } from "../../utilities/utilities";

import "../../scss/components/watches/WatchedApps.scss";
import "../../scss/components/watches/WatchCard.scss";
Expand All @@ -15,18 +14,12 @@ export class GitOps extends React.Component {
history: PropTypes.object.isRequired,
};

render() {
const { listClustersQuery } = this.props;

if (this.props.listClustersQuery.loading) {
return (
<div className="flex-column flex1 alignItems--center justifyContent--center">
<Loader size="60" />
</div>
)
}
componentDidMount() {
this.getClusters();
}

const hasClusters = listClustersQuery.listClusters?.length && listClustersQuery.listClusters[0];
render() {
const hasClusters = this.state && this.state.clusters && this.state.clusters?.length && this.state.clusters[0];

return (
<div className="ClusterDashboard--wrapper container flex-column flex1 u-overflow--auto">
Expand All @@ -43,15 +36,27 @@ export class GitOps extends React.Component {
</div>
);
}

getClusters = async () => {
fetch(`${window.env.API_ENDPOINT}/clusters/list`, {
method: "GET",
headers: {
"Authorization": Utilities.getToken(),
"Content-Type": "application/json",
}
}).then(async (response) => {
const data = await response.json();
this.setState({
clusters: data,
})
return data;
}).catch((error) => {
console.log(error);
});
}
}

export default compose(
withRouter,
withApollo,
graphql(listClusters, {
name: "listClustersQuery",
options: {
fetchPolicy: "network-only"
}
}),
)(GitOps);
6 changes: 1 addition & 5 deletions kotsadm/web/src/components/shared/NavBar.jsx
Expand Up @@ -5,7 +5,6 @@ import { Link, withRouter } from "react-router-dom";
import { compose, withApollo } from "react-apollo";

import { Utilities } from "@src/utilities/utilities";
import { listClusters } from "@src/queries/ClusterQueries";
import Avatar from "../shared/Avatar";
import ErrorModal from "../modals/ErrorModal";

Expand Down Expand Up @@ -87,10 +86,7 @@ export class NavBar extends PureComponent {

handleGoToGitOps = () => {
if (this.props.location.pathname === "/gitops") {
this.props.client.query({
query: listClusters,
fetchPolicy: "network-only",
});

} else {
this.props.history.push("/gitops");
}
Expand Down

0 comments on commit f89042c

Please sign in to comment.