Skip to content

Commit

Permalink
Migrate getKotsPreflightResult to go api
Browse files Browse the repository at this point in the history
  • Loading branch information
emosbaugh committed Aug 18, 2020
1 parent c681a92 commit 0738756
Show file tree
Hide file tree
Showing 14 changed files with 262 additions and 409 deletions.
69 changes: 0 additions & 69 deletions kotsadm/api/src/preflight/preflight_store.ts
Expand Up @@ -20,75 +20,6 @@ export class PreflightStore {
private readonly pool: pg.Pool
) {}

async getKotsPreflightResult(appId: string, clusterId: string, sequence: number): Promise<PreflightResult> {
const q =
`SELECT
app_downstream_version.preflight_result,
app_downstream_version.preflight_result_created_at,
app.slug as app_slug,
cluster.slug as cluster_slug
FROM app_downstream_version
INNER JOIN app ON app_downstream_version.app_id = app.id
INNER JOIN cluster ON app_downstream_version.cluster_id = cluster.id
WHERE
app_downstream_version.app_id = $1 AND
app_downstream_version.cluster_id = $2 AND
app_downstream_version.sequence = $3`;

const v = [
appId,
clusterId,
sequence,
];

const result = await this.pool.query(q,v);

if (result.rows.length === 0) {
throw new Error(`Couldn't find preflight spec with appId: ${appId}, clusterId: ${clusterId}, sequence: ${sequence}`);
}

const preflightResult = new PreflightResult();
preflightResult.appSlug = result.rows[0].app_slug;
preflightResult.clusterSlug = result.rows[0].cluster_slug;
preflightResult.result = result.rows[0].preflight_result;
preflightResult.createdAt = result.rows[0].preflight_result_created_at;

return preflightResult;

}

async getLatestKotsPreflightResult(): Promise<PreflightResult> {
const q = `SELECT id FROM app WHERE current_sequence = 0 ORDER BY created_at DESC LIMIT 1`;
const r = await this.pool.query(q);
if (r.rows.length === 0) {
throw new ReplicatedError(`No app has been installed yet`);
}
const appId = r.rows[0].id;

const qq =
`SELECT
app_downstream_version.preflight_result,
app_downstream_version.preflight_result_created_at,
app.slug as app_slug,
cluster.slug as cluster_slug
FROM app_downstream_version
INNER JOIN app ON app_downstream_version.app_id = app.id
INNER JOIN cluster ON app_downstream_version.cluster_id = cluster.id
WHERE
app_downstream_version.app_id = $1 AND
app_downstream_version.sequence = 0`;

const vv = [ appId ];
const result = await this.pool.query(qq, vv);
const preflightResult = new PreflightResult();
preflightResult.appSlug = result.rows[0].app_slug;
preflightResult.clusterSlug = result.rows[0].cluster_slug;
preflightResult.result = result.rows[0].preflight_result;
preflightResult.createdAt = result.rows[0].preflight_result_created_at;

return preflightResult;
}

async getPendingPreflightParams(inCluster: boolean): Promise<PreflightParams[]> {
const params = await Params.getParams();
const q =
Expand Down
15 changes: 0 additions & 15 deletions kotsadm/api/src/preflight/resolvers/preflight_queries.ts
Expand Up @@ -5,21 +5,6 @@ import { Stores } from "../../schema/stores";

export function PrefightQueries(stores: Stores) {
return {
async getKotsPreflightResult(root: any, args: any, context: Context): Promise<PreflightResult> {
const { appSlug, clusterSlug, sequence } = args;

const appId = await stores.kotsAppStore.getIdFromSlug(appSlug);
const clusterId = await stores.clusterStore.getIdFromSlug(clusterSlug);

const result = await stores.preflightStore.getKotsPreflightResult(appId, clusterId, sequence);
return result;
},

async getLatestKotsPreflightResult(root: any, args: any, context: Context): Promise<PreflightResult> {
const result = await stores.preflightStore.getLatestKotsPreflightResult();
return result;
},

async getPreflightCommand(root: any, args: any, context: Context): Promise<string> {
const { appSlug, clusterSlug, sequence } = args;
return await stores.preflightStore.getPreflightCommand(appSlug, clusterSlug, sequence);
Expand Down
2 changes: 0 additions & 2 deletions kotsadm/api/src/schema/query.ts
Expand Up @@ -38,8 +38,6 @@ export const Query = `
getSupportBundle(watchSlug: String!): SupportBundle
getSupportBundleCommand(watchSlug: String): String
getKotsPreflightResult(appSlug: String!, clusterSlug: String!, sequence: Int!): PreflightResult
getLatestKotsPreflightResult: PreflightResult
getPreflightCommand(appSlug: String, clusterSlug: String, sequence: String): String
getAirgapInstallStatus: InstallStatus
Expand Down
2 changes: 2 additions & 0 deletions kotsadm/pkg/apiserver/server.go
Expand Up @@ -103,6 +103,8 @@ func Start() {
r.Path("/api/v1/license/platform").Methods("OPTIONS", "POST").HandlerFunc(handlers.ExchangePlatformLicense)
r.Path("/api/v1/app/{appSlug}/sequence/{sequence}/preflight/ignore-rbac").Methods("OPTIONS", "POST").HandlerFunc(handlers.IgnorePreflightRBACErrors)
r.Path("/api/v1/app/{appSlug}/sequence/{sequence}/preflight/run").Methods("OPTIONS", "POST").HandlerFunc(handlers.StartPreflightChecks)
r.Path("/api/v1/app/{appSlug}/sequence/{sequence}/preflight/result").Methods("OPTIONS", "GET").HandlerFunc(handlers.GetPreflightResult)
r.Path("/api/v1/preflight/result").Methods("OPTIONS", "GET").HandlerFunc(handlers.GetLatestPreflightResult)
r.Path("/api/v1/upload").Methods("PUT").HandlerFunc(handlers.UploadExistingApp)
r.Path("/api/v1/download").Methods("GET").HandlerFunc(handlers.DownloadApp)
r.Path("/api/v1/app/{appSlug}/sequence/{sequence}/deploy").Methods("OPTIONS", "POST").HandlerFunc(handlers.DeployAppVersion)
Expand Down
72 changes: 72 additions & 0 deletions kotsadm/pkg/downstream/downstream.go
Expand Up @@ -163,6 +163,55 @@ func GetIgnoreRBACErrors(appID string, sequence int64) (bool, error) {
return shouldIgnore.Bool, nil
}

func GetPreflightResult(appID string, sequence int64) (*types.PreflightResult, error) {
db := persistence.MustGetPGSession()
query := `
SELECT
app_downstream_version.preflight_result,
app_downstream_version.preflight_result_created_at,
app.slug as app_slug,
cluster.slug as cluster_slug
FROM app_downstream_version
INNER JOIN app ON app_downstream_version.app_id = app.id
INNER JOIN cluster ON app_downstream_version.cluster_id = cluster.id
WHERE
app_downstream_version.app_id = $1 AND
app_downstream_version.sequence = $2`

row := db.QueryRow(query, appID, sequence)
r, err := preflightResultFromRow(row)
if err != nil {
return nil, errors.Wrap(err, "failed to get preflight result from row")
}

return r, nil
}

func GetLatestPreflightResult() (*types.PreflightResult, error) {
db := persistence.MustGetPGSession()
query := `
SELECT
app_downstream_version.preflight_result,
app_downstream_version.preflight_result_created_at,
app.slug as app_slug,
cluster.slug as cluster_slug
FROM app_downstream_version
INNER JOIN (
SELECT id, slug FROM app WHERE current_sequence = 0 ORDER BY created_at DESC LIMIT 1
) AS app ON app_downstream_version.app_id = app.id
INNER JOIN cluster ON app_downstream_version.cluster_id = cluster.id
WHERE
app_downstream_version.sequence = 0`

row := db.QueryRow(query)
r, err := preflightResultFromRow(row)
if err != nil {
return nil, errors.Wrap(err, "failed to get preflight result from row")
}

return r, nil
}

func SetIgnorePreflightPermissionErrors(appID string, sequence int64) error {
db := persistence.MustGetPGSession()
query := `UPDATE app_downstream_version
Expand Down Expand Up @@ -431,6 +480,29 @@ func versionFromRow(appID string, row scannable) (*types.DownstreamVersion, erro
return v, nil
}

func preflightResultFromRow(row scannable) (*types.PreflightResult, error) {
r := &types.PreflightResult{}

var preflightResult sql.NullString
var preflightResultCreatedAt sql.NullTime

if err := row.Scan(
&preflightResult,
&preflightResultCreatedAt,
&r.AppSlug,
&r.ClusterSlug,
); err != nil {
return nil, errors.Wrap(err, "failed to scan")
}

r.Result = preflightResult.String
if preflightResultCreatedAt.Valid {
r.CreatedAt = &preflightResultCreatedAt.Time
}

return r, nil
}

func getReleaseNotes(appID string, parentSequence int64) (string, error) {
db := persistence.MustGetPGSession()
query := `SELECT release_notes FROM app_version WHERE app_id = $1 AND sequence = $2`
Expand Down
7 changes: 7 additions & 0 deletions kotsadm/pkg/downstream/types/types.go
Expand Up @@ -38,3 +38,10 @@ type DownstreamOutput struct {
ApplyStderr string `json:"applyStderr"`
RenderError string `json:"renderError"`
}

type PreflightResult struct {
Result string `json:"result"`
CreatedAt *time.Time `json:"createdAt"`
AppSlug string `json:"appSlug"`
ClusterSlug string `json:"clusterSlug"`
}
10 changes: 10 additions & 0 deletions kotsadm/pkg/handlers/cors.go
Expand Up @@ -8,3 +8,13 @@ func CORS(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")
}

func handleOptionsRequest(w http.ResponseWriter, r *http.Request) (isOptionsRequest bool) {
CORS(w, r)

if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return true
}
return false
}
84 changes: 70 additions & 14 deletions kotsadm/pkg/handlers/preflight.go
Expand Up @@ -8,17 +8,79 @@ import (
"github.com/gorilla/mux"
"github.com/replicatedhq/kots/kotsadm/pkg/app"
"github.com/replicatedhq/kots/kotsadm/pkg/downstream"
downstreamtypes "github.com/replicatedhq/kots/kotsadm/pkg/downstream/types"
"github.com/replicatedhq/kots/kotsadm/pkg/logger"
"github.com/replicatedhq/kots/kotsadm/pkg/preflight"
"github.com/replicatedhq/kots/kotsadm/pkg/version"
)

func IgnorePreflightRBACErrors(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")
type GetPreflightResultResponse struct {
PreflightResult downstreamtypes.PreflightResult `json:"preflightResult"`
}

func GetPreflightResult(w http.ResponseWriter, r *http.Request) {
if handleOptionsRequest(w, r) {
return
}

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

appSlug := mux.Vars(r)["appSlug"]
sequence, err := strconv.ParseInt(mux.Vars(r)["sequence"], 10, 64)
if err != nil {
logger.Error(err)
w.WriteHeader(400)
return
}

foundApp, err := app.GetFromSlug(appSlug)
if err != nil {
logger.Error(err)
w.WriteHeader(500)
return
}

result, err := downstream.GetPreflightResult(foundApp.ID, sequence)
if err != nil {
logger.Error(err)
w.WriteHeader(500)
return
}

response := GetPreflightResultResponse{
PreflightResult: *result,
}
JSON(w, 200, response)
}

func GetLatestPreflightResult(w http.ResponseWriter, r *http.Request) {
if handleOptionsRequest(w, r) {
return
}

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

if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
result, err := downstream.GetLatestPreflightResult()
if err != nil {
logger.Error(err)
w.WriteHeader(500)
return
}

response := GetPreflightResultResponse{
PreflightResult: *result,
}
JSON(w, 200, response)
}

func IgnorePreflightRBACErrors(w http.ResponseWriter, r *http.Request) {
if handleOptionsRequest(w, r) {
return
}

Expand All @@ -28,8 +90,7 @@ func IgnorePreflightRBACErrors(w http.ResponseWriter, r *http.Request) {
}

appSlug := mux.Vars(r)["appSlug"]
sequenceStr := mux.Vars(r)["sequence"]
sequence, err := strconv.Atoi(sequenceStr)
sequence, err := strconv.Atoi(mux.Vars(r)["sequence"])
if err != nil {
logger.Error(err)
w.WriteHeader(400)
Expand Down Expand Up @@ -68,11 +129,7 @@ func IgnorePreflightRBACErrors(w http.ResponseWriter, r *http.Request) {
}

func StartPreflightChecks(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)
if handleOptionsRequest(w, r) {
return
}

Expand All @@ -82,8 +139,7 @@ func StartPreflightChecks(w http.ResponseWriter, r *http.Request) {
}

appSlug := mux.Vars(r)["appSlug"]
sequenceStr := mux.Vars(r)["sequence"]
sequence, err := strconv.Atoi(sequenceStr)
sequence, err := strconv.Atoi(mux.Vars(r)["sequence"])
if err != nil {
logger.Error(err)
w.WriteHeader(400)
Expand Down

0 comments on commit 0738756

Please sign in to comment.