github.com/docker/compose-on-kubernetes@v0.5.0/internal/controller/stackstatereconciler.go (about) 1 package controller 2 3 import ( 4 "github.com/docker/compose-on-kubernetes/api/compose/latest" 5 "github.com/docker/compose-on-kubernetes/api/labels" 6 "github.com/docker/compose-on-kubernetes/internal/stackresources" 7 "github.com/pkg/errors" 8 log "github.com/sirupsen/logrus" 9 appstypes "k8s.io/api/apps/v1" 10 coretypes "k8s.io/api/core/v1" 11 "k8s.io/apimachinery/pkg/api/meta" 12 ) 13 14 // NameAndNamespace is a name/namespace pair 15 type NameAndNamespace struct { 16 Namespace string 17 Name string 18 } 19 20 func (n *NameAndNamespace) objKey() string { 21 return stackresources.ObjKey(n.Namespace, n.Name) 22 } 23 24 func extractStackNameAndNamespace(obj interface{}) (NameAndNamespace, error) { 25 if stack, ok := obj.(*latest.Stack); ok { 26 return NameAndNamespace{Name: stack.Name, Namespace: stack.Namespace}, nil 27 } 28 m, err := meta.Accessor(obj) 29 if err != nil { 30 return NameAndNamespace{}, err 31 } 32 lbls := m.GetLabels() 33 if lbls == nil { 34 return NameAndNamespace{}, errors.New("resource is not owned by a stack") 35 } 36 stackName, ok := lbls[labels.ForStackName] 37 if !ok { 38 return NameAndNamespace{}, errors.New("resource is not owned by a stack") 39 } 40 namespace := m.GetNamespace() 41 return NameAndNamespace{Name: stackName, Namespace: namespace}, nil 42 } 43 44 func generateStatus(stack *latest.Stack, resources []interface{}) latest.StackStatus { 45 log.Debugf("Generating status for stack %s/%s", stack.Namespace, stack.Name) 46 remainingNames := make(map[string]struct{}) 47 for _, svc := range stack.Spec.Services { 48 remainingNames[svc.Name] = struct{}{} 49 } 50 for _, r := range resources { 51 switch v := r.(type) { 52 case *appstypes.Deployment: 53 desired := int32(1) 54 if v.Spec.Replicas != nil { 55 desired = *v.Spec.Replicas 56 } 57 if desired == v.Status.ReadyReplicas { 58 delete(remainingNames, v.Name) 59 } 60 log.Debugf("Deployment %s has %d/%d", v.Name, v.Status.ReadyReplicas, desired) 61 case *appstypes.StatefulSet: 62 desired := int32(1) 63 if v.Spec.Replicas != nil { 64 desired = *v.Spec.Replicas 65 } 66 if desired == v.Status.ReadyReplicas { 67 delete(remainingNames, v.Name) 68 } 69 log.Debugf("Statefulset %s has %d/%d", v.Name, v.Status.ReadyReplicas, desired) 70 case *appstypes.DaemonSet: 71 if v.Status.NumberUnavailable == 0 { 72 delete(remainingNames, v.Name) 73 } 74 log.Debugf("Daemonset %s has %d unavailable", v.Name, v.Status.NumberUnavailable) 75 case *coretypes.Service: 76 // ignore 77 default: 78 log.Warnf("Unexpected type %T", v) 79 } 80 } 81 if len(remainingNames) != 0 { 82 log.Debugf("Services %v have not been seen", remainingNames) 83 return statusProgressing() 84 } 85 log.Debugf("Stack is available") 86 return statusAvailable() 87 } 88 89 func statusAvailable() latest.StackStatus { 90 return latest.StackStatus{ 91 Phase: latest.StackAvailable, 92 Message: "Stack is started", 93 } 94 } 95 96 func byStackIndexer(obj interface{}) ([]string, error) { 97 m, err := meta.Accessor(obj) 98 if err != nil { 99 return nil, err 100 } 101 lbls := m.GetLabels() 102 if lbls == nil { 103 return []string{}, nil 104 } 105 stackName, ok := lbls[labels.ForStackName] 106 if !ok { 107 return []string{}, nil 108 } 109 namespace := m.GetNamespace() 110 if namespace == "" { 111 return []string{stackName}, nil 112 } 113 return []string{stackresources.ObjKey(namespace, stackName)}, nil 114 }