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 // parse out deployment status and inject into service metadata
if len(kdep.Status.Conditions) > 0 { 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 svc.Metadata["started"] = kdep.Status.Conditions[0].LastUpdateTime
} else { } else {
svc.Status("n/a", nil) svc.Status(runtime.Unknown, nil)
} }
// get the real status // get the real status
for _, item := range podList.Items { for _, item := range podList.Items {
var status string
// check the name // check the name
if item.Metadata.Labels["name"] != name { if item.Metadata.Labels["name"] != name {
continue continue
@@ -203,12 +202,7 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
continue continue
} }
switch item.Status.Phase { status := transformStatus(item.Status.Phase)
case "Failed":
status = item.Status.Reason
default:
status = item.Status.Phase
}
// skip if we can't get the container // skip if we can't get the container
if len(item.Status.Containers) == 0 { 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 // set status from waiting
if v := state.Waiting; v != nil { if v := state.Waiting; v != nil {
if len(v.Reason) > 0 { status = runtime.Pending
status = v.Reason
}
} }
// TODO: set from terminated
svc.Status(status, nil) svc.Status(status, nil)
} }
@@ -744,3 +736,34 @@ func (k *kubernetes) DeleteNamespace(ns string) error {
} }
return err 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) { if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to create deployment: %v", err) logger.Debugf("Runtime failed to create deployment: %v", err)
} }
s.Status("error", err) s.Status(runtime.Error, err)
v := parseError(err) v := parseError(err)
if v.Reason == "AlreadyExists" { if v.Reason == "AlreadyExists" {
return runtime.ErrAlreadyExists 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) { if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to create service: %v", err) logger.Debugf("Runtime failed to create service: %v", err)
} }
s.Status("error", err) s.Status(runtime.Error, err)
v := parseError(err) v := parseError(err)
if v.Reason == "AlreadyExists" { if v.Reason == "AlreadyExists" {
return runtime.ErrAlreadyExists return runtime.ErrAlreadyExists
@@ -169,7 +169,7 @@ func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
return err return err
} }
s.Status("started", nil) s.Status(runtime.Running, nil)
return 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) { if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to delete service: %v", err) logger.Debugf("Runtime failed to delete service: %v", err)
} }
s.Status("error", err) s.Status(runtime.Error, err)
return err return err
} }
// delete deployment once the service has been deleted // 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) { if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to delete deployment: %v", err) logger.Debugf("Runtime failed to delete deployment: %v", err)
} }
s.Status("error", err) s.Status(runtime.Error, err)
return err return err
} }
s.Status("stopped", nil) s.Status(runtime.Stopped, nil)
return 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) { if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime failed to update deployment: %v", err) logger.Debugf("Runtime failed to update deployment: %v", err)
} }
s.Status("error", err) s.Status(runtime.Error, err)
return err return err
} }
if err := k.Update(serviceResource(s.kservice), opts...); err != nil { 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 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) s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
if err == nil { if err == nil {
s.Metadata["status"] = status
delete(s.Metadata, "error") delete(s.Metadata, "error")
return return
} }
s.Metadata["status"] = "error"
s.Metadata["error"] = err.Error() s.Metadata["error"] = err.Error()
} }

View File

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

View File

@@ -97,6 +97,29 @@ type Event struct {
Options *CreateOptions 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 // Service is runtime service
type Service struct { type Service struct {
// Name of the service // Name of the service
@@ -107,6 +130,8 @@ type Service struct {
Source string Source string
// Metadata stores metadata // Metadata stores metadata
Metadata map[string]string Metadata map[string]string
// Status of the service
Status ServiceStatus
} }
// Resources which are allocated to a serivce // Resources which are allocated to a serivce