blob: 82638035213dc0612c573666fae3260c2f47e731 [file] [log] [blame]
package status
import (
"bytes"
"encoding/json"
"fmt"
"strings"
)
type InstanceMonitor struct {
m Monitor
instances map[string]ResourceOuts
}
func NewInstanceMonitor(m Monitor) *InstanceMonitor {
return &InstanceMonitor{
m: m,
instances: map[string]ResourceOuts{},
}
}
func (m *InstanceMonitor) Monitor(id string, resources ResourceOuts) {
m.instances[id] = resources
}
func (m *InstanceMonitor) Get(id string) (map[DodoResource]Status, error) {
ret := map[DodoResource]Status{}
namespace := m.instances[id].Release.Namespace
for _, out := range m.instances[id].Outs {
if _, err := m.monitor(namespace, DodoResource{"internal", out.Name}, out, ret); err != nil {
return nil, err
}
}
for i := range ret {
if i.Type == "internal" {
delete(ret, i)
}
}
return ret, nil
}
func mergeStatus(a Status, b Status) Status {
if a > b {
return a
} else {
return b
}
}
// TODO(gio): handle volume
func (m *InstanceMonitor) monitor(namespace string, resource DodoResource, out ResourceOut, ret map[DodoResource]Status) (Status, error) {
status := StatusNoStatus
if resource.Type == "ingress" {
var err error
status, err = m.m.Get(Resource{
Type: ResourceIngress,
ResourceRef: ResourceRef{
Id: out.Id,
Name: fmt.Sprintf("ingress-%s", strings.TrimPrefix(resource.Name, "https://")),
Namespace: namespace,
},
})
if err != nil {
return StatusNoStatus, err
}
} else {
for _, h := range out.Helm {
hs, err := m.m.Get(Resource{
Type: ResourceHelmRelease,
ResourceRef: ResourceRef{
Id: h.Id,
Name: h.Name,
Namespace: namespace,
},
})
if err != nil {
return StatusNoStatus, err
}
status = mergeStatus(status, hs)
}
}
for _, i := range out.Volume {
if s, err := m.monitor(namespace, DodoResource{"volume", i.Name}, i, ret); err != nil {
return StatusNoStatus, err
} else {
status = mergeStatus(status, s)
}
}
for _, i := range out.PostgreSQL {
if s, err := m.monitor(namespace, DodoResource{"postgresql", i.Name}, i, ret); err != nil {
return StatusNoStatus, err
} else {
status = mergeStatus(status, s)
}
}
for _, i := range out.MongoDB {
if s, err := m.monitor(namespace, DodoResource{"mongodb", i.Name}, i, ret); err != nil {
return StatusNoStatus, err
} else {
status = mergeStatus(status, s)
}
}
for _, i := range out.Ingress {
name := fmt.Sprintf("https://%s.%s", i.Subdomain, i.Network.Domain)
if s, err := m.monitor(namespace, DodoResource{"ingress", name}, i.ResourceOut, ret); err != nil {
return StatusNoStatus, err
} else {
status = mergeStatus(status, s)
}
}
for _, i := range out.Services {
if s, err := m.monitor(namespace, DodoResource{"service", i.Name}, i, ret); err != nil {
return StatusNoStatus, err
} else {
status = mergeStatus(status, s)
}
}
ret[resource] = status
return status, nil
}
type resourceIngress struct {
ResourceOut
Network struct {
Domain string `json:"domain"`
} `json:"network"`
Subdomain string `json:"subdomain"`
}
type resourceHelm struct {
Id string `json:"id"`
Name string `json:"name"`
}
type ResourceOut struct {
Id string `json:"id"`
Name string `json:"name"`
Volume map[string]ResourceOut `json:"volume"`
PostgreSQL map[string]ResourceOut `json:"postgresql"`
MongoDB map[string]ResourceOut `json:"mongodb"`
Ingress map[string]resourceIngress `json:"ingress"`
Services map[string]ResourceOut `json:"services"`
Helm map[string]resourceHelm `json:"helmR"`
}
type ResourceOuts struct {
Release struct {
Namespace string `json:"namespace"`
}
Outs map[string]ResourceOut `json:"outs"`
}
type DodoResource struct {
Type string
Name string
}
type DodoResourceStatus struct {
Type string `json:"type"`
Name string `json:"name"`
Status string `json:"status"`
}
func DecodeResourceOuts(raw []byte) (ResourceOuts, error) {
var outs ResourceOuts
if err := json.NewDecoder(bytes.NewReader(raw)).Decode(&outs); err != nil {
return ResourceOuts{}, err
}
return outs, nil
}