Skip to content

Commit 6fcde99

Browse files
authored
Add endpoints to trigger preflight checks and return their status / results (#2613)
* Add endpoints to trigger preflight checks and return their status / results
1 parent 5659a9d commit 6fcde99

File tree

37 files changed

+1812
-34
lines changed

37 files changed

+1812
-34
lines changed

api/client/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ type Client interface {
1919
GetLinuxAppConfigValues() (types.AppConfigValues, error)
2020
PatchLinuxAppConfigValues(types.AppConfigValues) (types.AppConfigValues, error)
2121
TemplateLinuxAppConfig(values types.AppConfigValues) (types.AppConfig, error)
22+
RunLinuxAppPreflights() (types.InstallAppPreflightsStatusResponse, error)
23+
GetLinuxAppPreflightsStatus() (types.InstallAppPreflightsStatusResponse, error)
2224

2325
GetKubernetesInstallationConfig() (types.KubernetesInstallationConfig, error)
2426
ConfigureKubernetesInstallation(config types.KubernetesInstallationConfig) (types.Status, error)
@@ -28,6 +30,8 @@ type Client interface {
2830
GetKubernetesAppConfigValues() (types.AppConfigValues, error)
2931
PatchKubernetesAppConfigValues(types.AppConfigValues) (types.AppConfigValues, error)
3032
TemplateKubernetesAppConfig(values types.AppConfigValues) (types.AppConfig, error)
33+
RunKubernetesAppPreflights() (types.InstallAppPreflightsStatusResponse, error)
34+
GetKubernetesAppPreflightsStatus() (types.InstallAppPreflightsStatusResponse, error)
3135
}
3236

3337
type client struct {

api/client/client_test.go

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,3 +958,259 @@ func TestKubernetesTemplateAppConfig(t *testing.T) {
958958
assert.Equal(t, "APPLICATION NAME", config.Groups[0].Items[0].Title)
959959
assert.Equal(t, "myapp", config.Groups[0].Items[0].Value.StrVal)
960960
}
961+
962+
func TestRunLinuxAppPreflights(t *testing.T) {
963+
// Create a test server
964+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
965+
assert.Equal(t, "POST", r.Method)
966+
assert.Equal(t, "/api/linux/install/app-preflights/run", r.URL.Path)
967+
968+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
969+
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
970+
971+
// Return successful response
972+
w.WriteHeader(http.StatusOK)
973+
json.NewEncoder(w).Encode(types.InstallAppPreflightsStatusResponse{
974+
Status: types.Status{
975+
State: types.StateRunning,
976+
Description: "App preflights running",
977+
},
978+
Output: &types.PreflightsOutput{
979+
Pass: []types.PreflightsRecord{
980+
{
981+
Title: "App Dependencies",
982+
Message: "All dependencies available",
983+
},
984+
},
985+
},
986+
Titles: []string{"App Dependencies"},
987+
})
988+
}))
989+
defer server.Close()
990+
991+
// Test successful run
992+
c := New(server.URL, WithToken("test-token"))
993+
status, err := c.RunLinuxAppPreflights()
994+
assert.NoError(t, err)
995+
assert.Equal(t, types.StateRunning, status.Status.State)
996+
assert.Equal(t, "App preflights running", status.Status.Description)
997+
assert.Equal(t, "App Dependencies", status.Output.Pass[0].Title)
998+
assert.Equal(t, "All dependencies available", status.Output.Pass[0].Message)
999+
assert.Equal(t, []string{"App Dependencies"}, status.Titles)
1000+
1001+
// Test error response
1002+
errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1003+
w.WriteHeader(http.StatusConflict)
1004+
json.NewEncoder(w).Encode(types.APIError{
1005+
StatusCode: http.StatusConflict,
1006+
Message: "App preflights already running",
1007+
})
1008+
}))
1009+
defer errorServer.Close()
1010+
1011+
c = New(errorServer.URL, WithToken("test-token"))
1012+
status, err = c.RunLinuxAppPreflights()
1013+
assert.Error(t, err)
1014+
assert.Equal(t, types.InstallAppPreflightsStatusResponse{}, status)
1015+
1016+
apiErr, ok := err.(*types.APIError)
1017+
require.True(t, ok, "Expected err to be of type *types.APIError")
1018+
assert.Equal(t, http.StatusConflict, apiErr.StatusCode)
1019+
assert.Equal(t, "App preflights already running", apiErr.Message)
1020+
}
1021+
1022+
func TestGetLinuxAppPreflightsStatus(t *testing.T) {
1023+
// Create a test server
1024+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1025+
assert.Equal(t, "GET", r.Method)
1026+
assert.Equal(t, "/api/linux/install/app-preflights/status", r.URL.Path)
1027+
1028+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
1029+
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
1030+
1031+
// Return successful response
1032+
w.WriteHeader(http.StatusOK)
1033+
json.NewEncoder(w).Encode(types.InstallAppPreflightsStatusResponse{
1034+
Status: types.Status{
1035+
State: types.StateSucceeded,
1036+
Description: "App preflights succeeded",
1037+
},
1038+
Output: &types.PreflightsOutput{
1039+
Pass: []types.PreflightsRecord{
1040+
{
1041+
Title: "Storage Check",
1042+
Message: "Sufficient storage available",
1043+
},
1044+
},
1045+
Fail: []types.PreflightsRecord{
1046+
{
1047+
Title: "Network Check",
1048+
Message: "Network connectivity issues",
1049+
},
1050+
},
1051+
},
1052+
Titles: []string{"Storage Check", "Network Check"},
1053+
})
1054+
}))
1055+
defer server.Close()
1056+
1057+
// Test successful get
1058+
c := New(server.URL, WithToken("test-token"))
1059+
status, err := c.GetLinuxAppPreflightsStatus()
1060+
assert.NoError(t, err)
1061+
assert.Equal(t, types.StateSucceeded, status.Status.State)
1062+
assert.Equal(t, "App preflights succeeded", status.Status.Description)
1063+
assert.Equal(t, "Storage Check", status.Output.Pass[0].Title)
1064+
assert.Equal(t, "Sufficient storage available", status.Output.Pass[0].Message)
1065+
assert.Equal(t, "Network Check", status.Output.Fail[0].Title)
1066+
assert.Equal(t, "Network connectivity issues", status.Output.Fail[0].Message)
1067+
assert.Equal(t, []string{"Storage Check", "Network Check"}, status.Titles)
1068+
1069+
// Test error response
1070+
errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1071+
w.WriteHeader(http.StatusInternalServerError)
1072+
json.NewEncoder(w).Encode(types.APIError{
1073+
StatusCode: http.StatusInternalServerError,
1074+
Message: "Internal Server Error",
1075+
})
1076+
}))
1077+
defer errorServer.Close()
1078+
1079+
c = New(errorServer.URL, WithToken("test-token"))
1080+
status, err = c.GetLinuxAppPreflightsStatus()
1081+
assert.Error(t, err)
1082+
assert.Equal(t, types.InstallAppPreflightsStatusResponse{}, status)
1083+
1084+
apiErr, ok := err.(*types.APIError)
1085+
require.True(t, ok, "Expected err to be of type *types.APIError")
1086+
assert.Equal(t, http.StatusInternalServerError, apiErr.StatusCode)
1087+
assert.Equal(t, "Internal Server Error", apiErr.Message)
1088+
}
1089+
1090+
func TestRunKubernetesAppPreflights(t *testing.T) {
1091+
// Create a test server
1092+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1093+
assert.Equal(t, "POST", r.Method)
1094+
assert.Equal(t, "/api/kubernetes/install/app-preflights/run", r.URL.Path)
1095+
1096+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
1097+
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
1098+
1099+
// Return successful response
1100+
w.WriteHeader(http.StatusOK)
1101+
json.NewEncoder(w).Encode(types.InstallAppPreflightsStatusResponse{
1102+
Status: types.Status{
1103+
State: types.StateRunning,
1104+
Description: "App preflights running on Kubernetes",
1105+
},
1106+
Output: &types.PreflightsOutput{
1107+
Pass: []types.PreflightsRecord{
1108+
{
1109+
Title: "Cluster Resources",
1110+
Message: "Sufficient cluster resources",
1111+
},
1112+
},
1113+
},
1114+
Titles: []string{"Cluster Resources"},
1115+
})
1116+
}))
1117+
defer server.Close()
1118+
1119+
// Test successful run
1120+
c := New(server.URL, WithToken("test-token"))
1121+
status, err := c.RunKubernetesAppPreflights()
1122+
assert.NoError(t, err)
1123+
assert.Equal(t, types.StateRunning, status.Status.State)
1124+
assert.Equal(t, "App preflights running on Kubernetes", status.Status.Description)
1125+
assert.Equal(t, "Cluster Resources", status.Output.Pass[0].Title)
1126+
assert.Equal(t, "Sufficient cluster resources", status.Output.Pass[0].Message)
1127+
assert.Equal(t, []string{"Cluster Resources"}, status.Titles)
1128+
1129+
// Test error response
1130+
errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1131+
w.WriteHeader(http.StatusConflict)
1132+
json.NewEncoder(w).Encode(types.APIError{
1133+
StatusCode: http.StatusConflict,
1134+
Message: "App preflights already running",
1135+
})
1136+
}))
1137+
defer errorServer.Close()
1138+
1139+
c = New(errorServer.URL, WithToken("test-token"))
1140+
status, err = c.RunKubernetesAppPreflights()
1141+
assert.Error(t, err)
1142+
assert.Equal(t, types.InstallAppPreflightsStatusResponse{}, status)
1143+
1144+
apiErr, ok := err.(*types.APIError)
1145+
require.True(t, ok, "Expected err to be of type *types.APIError")
1146+
assert.Equal(t, http.StatusConflict, apiErr.StatusCode)
1147+
assert.Equal(t, "App preflights already running", apiErr.Message)
1148+
}
1149+
1150+
func TestGetKubernetesAppPreflightsStatus(t *testing.T) {
1151+
// Create a test server
1152+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1153+
assert.Equal(t, "GET", r.Method)
1154+
assert.Equal(t, "/api/kubernetes/install/app-preflights/status", r.URL.Path)
1155+
1156+
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
1157+
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
1158+
1159+
// Return successful response
1160+
w.WriteHeader(http.StatusOK)
1161+
json.NewEncoder(w).Encode(types.InstallAppPreflightsStatusResponse{
1162+
Status: types.Status{
1163+
State: types.StateFailed,
1164+
Description: "App preflights failed on Kubernetes",
1165+
},
1166+
Output: &types.PreflightsOutput{
1167+
Pass: []types.PreflightsRecord{
1168+
{
1169+
Title: "RBAC Check",
1170+
Message: "Sufficient permissions",
1171+
},
1172+
},
1173+
Fail: []types.PreflightsRecord{
1174+
{
1175+
Title: "Storage Class",
1176+
Message: "No default storage class found",
1177+
},
1178+
},
1179+
},
1180+
Titles: []string{"RBAC Check", "Storage Class"},
1181+
})
1182+
}))
1183+
defer server.Close()
1184+
1185+
// Test successful get
1186+
c := New(server.URL, WithToken("test-token"))
1187+
status, err := c.GetKubernetesAppPreflightsStatus()
1188+
assert.NoError(t, err)
1189+
assert.Equal(t, types.StateFailed, status.Status.State)
1190+
assert.Equal(t, "App preflights failed on Kubernetes", status.Status.Description)
1191+
assert.Equal(t, "RBAC Check", status.Output.Pass[0].Title)
1192+
assert.Equal(t, "Sufficient permissions", status.Output.Pass[0].Message)
1193+
assert.Equal(t, "Storage Class", status.Output.Fail[0].Title)
1194+
assert.Equal(t, "No default storage class found", status.Output.Fail[0].Message)
1195+
assert.Equal(t, []string{"RBAC Check", "Storage Class"}, status.Titles)
1196+
1197+
// Test error response
1198+
errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1199+
w.WriteHeader(http.StatusInternalServerError)
1200+
json.NewEncoder(w).Encode(types.APIError{
1201+
StatusCode: http.StatusInternalServerError,
1202+
Message: "Internal Server Error",
1203+
})
1204+
}))
1205+
defer errorServer.Close()
1206+
1207+
c = New(errorServer.URL, WithToken("test-token"))
1208+
status, err = c.GetKubernetesAppPreflightsStatus()
1209+
assert.Error(t, err)
1210+
assert.Equal(t, types.InstallAppPreflightsStatusResponse{}, status)
1211+
1212+
apiErr, ok := err.(*types.APIError)
1213+
require.True(t, ok, "Expected err to be of type *types.APIError")
1214+
assert.Equal(t, http.StatusInternalServerError, apiErr.StatusCode)
1215+
assert.Equal(t, "Internal Server Error", apiErr.Message)
1216+
}

api/client/install.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,3 +491,111 @@ func (c *client) TemplateKubernetesAppConfig(values types.AppConfigValues) (type
491491

492492
return config, nil
493493
}
494+
495+
func (c *client) RunLinuxAppPreflights() (types.InstallAppPreflightsStatusResponse, error) {
496+
req, err := http.NewRequest("POST", c.apiURL+"/api/linux/install/app-preflights/run", nil)
497+
if err != nil {
498+
return types.InstallAppPreflightsStatusResponse{}, err
499+
}
500+
req.Header.Set("Content-Type", "application/json")
501+
setAuthorizationHeader(req, c.token)
502+
503+
resp, err := c.httpClient.Do(req)
504+
if err != nil {
505+
return types.InstallAppPreflightsStatusResponse{}, err
506+
}
507+
defer resp.Body.Close()
508+
509+
if resp.StatusCode != http.StatusOK {
510+
return types.InstallAppPreflightsStatusResponse{}, errorFromResponse(resp)
511+
}
512+
513+
var status types.InstallAppPreflightsStatusResponse
514+
err = json.NewDecoder(resp.Body).Decode(&status)
515+
if err != nil {
516+
return types.InstallAppPreflightsStatusResponse{}, err
517+
}
518+
519+
return status, nil
520+
}
521+
522+
func (c *client) GetLinuxAppPreflightsStatus() (types.InstallAppPreflightsStatusResponse, error) {
523+
req, err := http.NewRequest("GET", c.apiURL+"/api/linux/install/app-preflights/status", nil)
524+
if err != nil {
525+
return types.InstallAppPreflightsStatusResponse{}, err
526+
}
527+
req.Header.Set("Content-Type", "application/json")
528+
setAuthorizationHeader(req, c.token)
529+
530+
resp, err := c.httpClient.Do(req)
531+
if err != nil {
532+
return types.InstallAppPreflightsStatusResponse{}, err
533+
}
534+
defer resp.Body.Close()
535+
536+
if resp.StatusCode != http.StatusOK {
537+
return types.InstallAppPreflightsStatusResponse{}, errorFromResponse(resp)
538+
}
539+
540+
var status types.InstallAppPreflightsStatusResponse
541+
err = json.NewDecoder(resp.Body).Decode(&status)
542+
if err != nil {
543+
return types.InstallAppPreflightsStatusResponse{}, err
544+
}
545+
546+
return status, nil
547+
}
548+
549+
func (c *client) RunKubernetesAppPreflights() (types.InstallAppPreflightsStatusResponse, error) {
550+
req, err := http.NewRequest("POST", c.apiURL+"/api/kubernetes/install/app-preflights/run", nil)
551+
if err != nil {
552+
return types.InstallAppPreflightsStatusResponse{}, err
553+
}
554+
req.Header.Set("Content-Type", "application/json")
555+
setAuthorizationHeader(req, c.token)
556+
557+
resp, err := c.httpClient.Do(req)
558+
if err != nil {
559+
return types.InstallAppPreflightsStatusResponse{}, err
560+
}
561+
defer resp.Body.Close()
562+
563+
if resp.StatusCode != http.StatusOK {
564+
return types.InstallAppPreflightsStatusResponse{}, errorFromResponse(resp)
565+
}
566+
567+
var status types.InstallAppPreflightsStatusResponse
568+
err = json.NewDecoder(resp.Body).Decode(&status)
569+
if err != nil {
570+
return types.InstallAppPreflightsStatusResponse{}, err
571+
}
572+
573+
return status, nil
574+
}
575+
576+
func (c *client) GetKubernetesAppPreflightsStatus() (types.InstallAppPreflightsStatusResponse, error) {
577+
req, err := http.NewRequest("GET", c.apiURL+"/api/kubernetes/install/app-preflights/status", nil)
578+
if err != nil {
579+
return types.InstallAppPreflightsStatusResponse{}, err
580+
}
581+
req.Header.Set("Content-Type", "application/json")
582+
setAuthorizationHeader(req, c.token)
583+
584+
resp, err := c.httpClient.Do(req)
585+
if err != nil {
586+
return types.InstallAppPreflightsStatusResponse{}, err
587+
}
588+
defer resp.Body.Close()
589+
590+
if resp.StatusCode != http.StatusOK {
591+
return types.InstallAppPreflightsStatusResponse{}, errorFromResponse(resp)
592+
}
593+
594+
var status types.InstallAppPreflightsStatusResponse
595+
err = json.NewDecoder(resp.Body).Decode(&status)
596+
if err != nil {
597+
return types.InstallAppPreflightsStatusResponse{}, err
598+
}
599+
600+
return status, nil
601+
}

0 commit comments

Comments
 (0)