runtime: normalised service statuses (#1994)

This commit is contained in:
ben-toogood
2020-09-10 12:17:11 +01:00
committed by GitHub
parent acd3bea0c6
commit b8f79a3fc6
4 changed files with 81 additions and 33 deletions

View File

@@ -184,16 +184,15 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
// parse out deployment status and inject into service metadata
if len(kdep.Status.Conditions) > 0 {
svc.Status(kdep.Status.Conditions[0].Type, nil)
status := transformStatus(kdep.Status.Conditions[0].Type)
svc.Status(status, nil)
svc.Metadata["started"] = kdep.Status.Conditions[0].LastUpdateTime
} else {
svc.Status("n/a", nil)
svc.Status(runtime.Unknown, nil)
}
// get the real status
for _, item := range podList.Items {
var status string
// check the name
if item.Metadata.Labels["name"] != name {
continue
@@ -203,12 +202,7 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
continue
}
switch item.Status.Phase {
case "Failed":
status = item.Status.Reason
default:
status = item.Status.Phase
}
status := transformStatus(item.Status.Phase)
// skip if we can't get the container
if len(item.Status.Containers) == 0 {
@@ -225,11 +219,9 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
// set status from waiting
if v := state.Waiting; v != nil {
if len(v.Reason) > 0 {
status = v.Reason
status = runtime.Pending
}
}
// TODO: set from terminated
svc.Status(status, nil)
}
@@ -744,3 +736,34 @@ func (k *kubernetes) DeleteNamespace(ns string) error {
}
return err
}
// transformStatus takes a deployment status (deploymentcondition.type) and transforms it into a
// runtime service status, e.g. containercreating => starting
func transformStatus(depStatus string) runtime.ServiceStatus {
switch strings.ToLower(depStatus) {
case "pending":
return runtime.Pending
case "containercreating":
return runtime.Starting
case "imagepullbackoff":
return runtime.Error
case "crashloopbackoff":
return runtime.Error
case "error":
return runtime.Error
case "running":
return runtime.Running
case "available":
return runtime.Running
case "succeeded":
return runtime.Stopped
case "failed":
return runtime.Error
case "waiting":
return runtime.Pending
case "terminated":
return runtime.Stopped
default:
return runtime.Unknown
}
}

View File

@@ -149,7 +149,7 @@ func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to create deployment: %v", err)
}
s.Status("error", err)
s.Status(runtime.Error, err)
v := parseError(err)
if v.Reason == "AlreadyExists" {
return runtime.ErrAlreadyExists
@@ -161,7 +161,7 @@ func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to create service: %v", err)
}
s.Status("error", err)
s.Status(runtime.Error, err)
v := parseError(err)
if v.Reason == "AlreadyExists" {
return runtime.ErrAlreadyExists
@@ -169,7 +169,7 @@ func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
return err
}
s.Status("started", nil)
s.Status(runtime.Running, nil)
return nil
}
@@ -180,7 +180,7 @@ func (s *service) Stop(k client.Client, opts ...client.DeleteOption) error {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to delete service: %v", err)
}
s.Status("error", err)
s.Status(runtime.Error, err)
return err
}
// delete deployment once the service has been deleted
@@ -188,11 +188,11 @@ func (s *service) Stop(k client.Client, opts ...client.DeleteOption) error {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to delete deployment: %v", err)
}
s.Status("error", err)
s.Status(runtime.Error, err)
return err
}
s.Status("stopped", nil)
s.Status(runtime.Stopped, nil)
return nil
}
@@ -202,7 +202,7 @@ func (s *service) Update(k client.Client, opts ...client.UpdateOption) error {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to update deployment: %v", err)
}
s.Status("error", err)
s.Status(runtime.Error, err)
return err
}
if err := k.Update(serviceResource(s.kservice), opts...); err != nil {
@@ -215,13 +215,13 @@ func (s *service) Update(k client.Client, opts ...client.UpdateOption) error {
return nil
}
func (s *service) Status(status string, err error) {
func (s *service) Status(status runtime.ServiceStatus, err error) {
s.Service.Status = status
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
if err == nil {
s.Metadata["status"] = status
delete(s.Metadata, "error")
return
}
s.Metadata["status"] = "error"
s.Metadata["error"] = err.Error()
}

View File

@@ -133,7 +133,7 @@ func (s *service) Start() error {
if s.Metadata == nil {
s.Metadata = make(map[string]string)
}
s.Status("starting", nil)
s.Status(runtime.Starting, nil)
// TODO: pull source & build binary
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
@@ -142,7 +142,7 @@ func (s *service) Start() error {
p, err := s.Process.Fork(s.Exec)
if err != nil {
s.Status("error", err)
s.Status(runtime.Error, err)
return err
}
// set the pid
@@ -150,7 +150,7 @@ func (s *service) Start() error {
// set to running
s.running = true
// set status
s.Status("running", nil)
s.Status(runtime.Running, nil)
// set started
s.Metadata["started"] = time.Now().Format(time.RFC3339)
@@ -165,9 +165,9 @@ func (s *service) Start() error {
}
// Status updates the status of the service. Assumes it's called under a lock as it mutates state
func (s *service) Status(status string, err error) {
func (s *service) Status(status runtime.ServiceStatus, err error) {
s.Service.Status = status
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
s.Metadata["status"] = status
if err == nil {
delete(s.Metadata, "error")
return
@@ -193,7 +193,7 @@ func (s *service) Stop() error {
}
// set status
s.Status("stopping", nil)
s.Status(runtime.Stopping, nil)
// kill the process
err := s.Process.Kill(s.PID)
@@ -203,7 +203,7 @@ func (s *service) Stop() error {
}
// set status
s.Status("stopped", err)
s.Status(runtime.Stopped, err)
// return the kill error
return err
@@ -240,12 +240,12 @@ func (s *service) Wait() {
logger.Errorf("Service %s terminated with error %s", s.Name, err)
}
s.retries++
s.Status("error", err)
s.Status(runtime.Error, err)
s.Metadata["retries"] = strconv.Itoa(s.retries)
s.err = err
} else {
s.Status("done", nil)
s.Status(runtime.Stopped, nil)
}
// no longer running

View File

@@ -97,6 +97,29 @@ type Event struct {
Options *CreateOptions
}
// ServiceStatus defines service statuses
type ServiceStatus int
const (
// Unknown indicates the status of the service is not known
Unknown ServiceStatus = iota
// Pending is the initial status of a service
Pending
// Building is the status when the service is being built
Building
// Starting is the status when the service has been started but is not yet ready to accept traffic
Starting
// Running is the status when the service is active and accepting traffic
Running
// Stopping is the status when a service is stopping
Stopping
// Stopped is the status when a service has been stopped or has completed
Stopped
// Error is the status when an error occured, this could be a build error or a run error. The error
// details can be found within the service's metadata
Error
)
// Service is runtime service
type Service struct {
// Name of the service
@@ -107,6 +130,8 @@ type Service struct {
Source string
// Metadata stores metadata
Metadata map[string]string
// Status of the service
Status ServiceStatus
}
// Resources which are allocated to a serivce