diff --git a/pkg/api/handlers/libpod/healthcheck.go b/pkg/api/handlers/libpod/healthcheck.go index 6c74500b9e43..6eb2ab0e3ce6 100644 --- a/pkg/api/handlers/libpod/healthcheck.go +++ b/pkg/api/handlers/libpod/healthcheck.go @@ -14,8 +14,30 @@ func RunHealthCheck(w http.ResponseWriter, r *http.Request) { if err != nil { if status == libpod.HealthCheckContainerNotFound { utils.ContainerNotFound(w, name, err) + return } + if status == libpod.HealthCheckNotDefined { + utils.Error(w, "no healthcheck defined", http.StatusConflict, err) + return + } + if status == libpod.HealthCheckContainerStopped { + utils.Error(w, "container not running", http.StatusConflict, err) + return + } + utils.InternalServerError(w, err) + return + } + ctr, err := runtime.LookupContainer(name) + if err != nil { utils.InternalServerError(w, err) + return } - utils.WriteResponse(w, http.StatusOK, status) + + hcLog, err := ctr.GetHealthCheckLog() + if err != nil { + utils.InternalServerError(w, err) + return + } + + utils.WriteResponse(w, http.StatusOK, hcLog) } diff --git a/pkg/api/server/register_healthcheck.go b/pkg/api/server/register_healthcheck.go index 5466e2905fe8..9c25e229f038 100644 --- a/pkg/api/server/register_healthcheck.go +++ b/pkg/api/server/register_healthcheck.go @@ -8,6 +8,29 @@ import ( ) func (s *APIServer) registerHealthCheckHandlers(r *mux.Router) error { + // swagger:operation GET /libpod/containers/{name:.*}/runhealthcheck libpod libpodRunHealthCheck + // --- + // tags: + // - containers + // summary: Run a container's healthcheck + // description: Execute the defined healthcheck and return information about the results + // parameters: + // - in: path + // name: name:.* + // type: string + // required: true + // description: the name or ID of the container + // produces: + // - application/json + // responses: + // 200: + // $ref: "#/responses/HealthcheckRun" + // 404: + // $ref: "#/responses/NoSuchContainer" + // 409: + // description: container has no healthcheck or is not running + // 500: + // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/libpod/containers/{name}/runhealthcheck"), s.APIHandler(libpod.RunHealthCheck)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index fc409d8165b4..f091e75da4cd 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -139,3 +139,10 @@ type ok struct { ok string } } + +// Volume list +// swagger:response HealthcheckRun +type swagHealthCheckRunResponse struct { + // in:body + Body libpod.HealthCheckResults +} diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go index dc607c1b32ec..9eeeb9682c00 100644 --- a/pkg/bindings/containers/healthcheck.go +++ b/pkg/bindings/containers/healthcheck.go @@ -2,21 +2,21 @@ package containers import ( "context" - "github.com/containers/libpod/pkg/bindings" "net/http" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/bindings" ) // RunHealthCheck executes the container's healthcheck and returns the health status of the // container. -func RunHealthCheck(ctx context.Context, nameOrID string) (*libpod.HealthCheckStatus, error) { +func RunHealthCheck(ctx context.Context, nameOrID string) (*libpod.HealthCheckResults, error) { conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } var ( - status libpod.HealthCheckStatus + status libpod.HealthCheckResults ) response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/runhealthcheck", nil, nameOrID) if err != nil { diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index f6ef4abecf74..d4815c3d708f 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -240,4 +240,49 @@ var _ = Describe("Podman containers ", func() { Expect(data.State.Status).To(Equal("exited")) }) + It("run healthcheck", func() { + bt.runPodman([]string{"run", "-d", "--name", "hc", "--health-interval", "disable", "--health-retries", "2", "--health-cmd", "ls / || exit 1", alpine.name, "top"}) + + // bogus name should result in 404 + _, err := containers.RunHealthCheck(connText, "foobar") + Expect(err).ToNot(BeNil()) + code, _ := bindings.CheckResponseCode(err) + Expect(code).To(BeNumerically("==", http.StatusNotFound)) + + // a container that has no healthcheck should be a 409 + var name = "top" + bt.RunTopContainer(&name, &falseFlag, nil) + _, err = containers.RunHealthCheck(connText, name) + Expect(err).ToNot(BeNil()) + code, _ = bindings.CheckResponseCode(err) + Expect(code).To(BeNumerically("==", http.StatusConflict)) + + // TODO for the life of me, i cannot get this to work. maybe another set + // of eyes will + // successful healthcheck + //status := "healthy" + //for i:=0; i < 10; i++ { + // result, err := containers.RunHealthCheck(connText, "hc") + // Expect(err).To(BeNil()) + // if result.Status != "healthy" { + // fmt.Println("Healthcheck container still starting, retrying in 1 second") + // time.Sleep(1 * time.Second) + // continue + // } + // status = result.Status + // break + //} + //Expect(status).To(Equal("healthy")) + + // TODO enable this when wait is working + // healthcheck on a stopped container should be a 409 + //err = containers.Stop(connText, "hc", nil) + //Expect(err).To(BeNil()) + //_, err = containers.Wait(connText, "hc") + //Expect(err).To(BeNil()) + //_, err = containers.RunHealthCheck(connText, "hc") + //code, _ = bindings.CheckResponseCode(err) + //Expect(code).To(BeNumerically("==", http.StatusConflict)) + }) + })