diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index dcdb7e92c..337686311 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -1,6 +1,11 @@ package appjson import ( + "encoding/json" + "fmt" + "os" + "strings" + "github.com/dokku/dokku/plugins/common" ) @@ -18,9 +23,10 @@ var ( // AppJSON is a struct that represents an app.json file as understood by Dokku type AppJSON struct { - Cron []CronCommand `json:"cron"` - Formation map[string]Formation `json:"formation"` - Scripts struct { + Cron []CronCommand `json:"cron"` + Formation map[string]Formation `json:"formation"` + Healthchecks map[string][]Healthcheck `json:"healthchecks"` + Scripts struct { Dokku struct { Predeploy string `json:"predeploy"` Postdeploy string `json:"postdeploy"` @@ -41,6 +47,43 @@ type Formation struct { MaxParallel *int `json:"max_parallel"` } +type Healthcheck struct { + Attempts int32 `json:"attempts,omitempty"` + Command []string `json:"command,omitempty"` + Content string `json:"content,omitempty"` + HTTPHeaders []HTTPHeader `json:"httpHeaders,omitempty"` + InitialDelay int32 `json:"initialDelay,omitempty"` + Listening bool `json:"listening,omitempty"` + Name string `json:"name,omitempty"` + Path string `json:"path,omitempty"` + Port int `json:"port,omitempty"` + Scheme string `json:"scheme,omitempty"` + Timeout int32 `json:"timeout,omitempty"` + Type HealthcheckType `json:"type,omitempty"` + Uptime int32 `json:"uptime,omitempty"` + Wait int32 `json:"wait,omitempty"` + Warn bool `json:"warn,omitempty"` + OnFailure *OnFailure `json:"onFailure,omitempty"` +} + +type HealthcheckType string + +const ( + HealthcheckType_Liveness HealthcheckType = "liveness" + HealthcheckType_Readiness HealthcheckType = "readiness" + HealthcheckType_Startup HealthcheckType = "startup" +) + +type HTTPHeader struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} + +type OnFailure struct { + Command []string `json:"command,omitempty"` + Url string `json:"url,omitempty"` +} + // GetAppjsonDirectory returns the directory containing a given app's extracted app.json file func GetAppjsonDirectory(appName string) string { return common.GetAppDataDirectory("app-json", appName) @@ -50,3 +93,26 @@ func GetAppjsonDirectory(appName string) string { func GetAppjsonPath(appName string) string { return getProcessSpecificAppJSONPath(appName) } + +// GetAppJSON returns the parsed app.json file for a given app +func GetAppJSON(appName string) (AppJSON, error) { + if !hasAppJSON(appName) { + return AppJSON{}, nil + } + + b, err := os.ReadFile(getProcessSpecificAppJSONPath(appName)) + if err != nil { + return AppJSON{}, fmt.Errorf("Cannot read app.json file: %v", err) + } + + if strings.TrimSpace(string(b)) == "" { + return AppJSON{}, nil + } + + var appJSON AppJSON + if err = json.Unmarshal(b, &appJSON); err != nil { + return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err) + } + + return appJSON, nil +} diff --git a/plugins/app-json/functions.go b/plugins/app-json/functions.go index e2b907dbd..ee2a9e690 100644 --- a/plugins/app-json/functions.go +++ b/plugins/app-json/functions.go @@ -79,28 +79,6 @@ func constructScript(command string, shell string, isHerokuishImage bool, isCnbI return []string{shell, "-c", strings.Join(script, " ")} } -func getAppJSON(appName string) (AppJSON, error) { - if !hasAppJSON(appName) { - return AppJSON{}, nil - } - - b, err := os.ReadFile(getProcessSpecificAppJSONPath(appName)) - if err != nil { - return AppJSON{}, fmt.Errorf("Cannot read app.json file: %v", err) - } - - if strings.TrimSpace(string(b)) == "" { - return AppJSON{}, nil - } - - var appJSON AppJSON - if err = json.Unmarshal(b, &appJSON); err != nil { - return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err) - } - - return appJSON, nil -} - func getAppJSONPath(appName string) string { directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "app-json", appName) return filepath.Join(directory, "app.json") @@ -118,7 +96,7 @@ func getProcessSpecificAppJSONPath(appName string) string { // getPhaseScript extracts app.json from app image and returns the appropriate json key/value func getPhaseScript(appName string, phase string) (string, error) { - appJSON, err := getAppJSON(appName) + appJSON, err := GetAppJSON(appName) if err != nil { return "", err } @@ -482,7 +460,7 @@ func createdContainerID(appName string, dockerArgs []string, image string, comma } func setScale(appName string, image string) error { - appJSON, err := getAppJSON(appName) + appJSON, err := GetAppJSON(appName) if err != nil { return err } diff --git a/plugins/app-json/triggers.go b/plugins/app-json/triggers.go index 4f33d12c8..843c6e448 100644 --- a/plugins/app-json/triggers.go +++ b/plugins/app-json/triggers.go @@ -13,7 +13,7 @@ import ( // TriggerAppJSONProcessDeployParallelism returns the max number of processes to deploy in parallel func TriggerAppJSONProcessDeployParallelism(appName string, processType string) error { - appJSON, err := getAppJSON(appName) + appJSON, err := GetAppJSON(appName) if err != nil { return err }