-
Notifications
You must be signed in to change notification settings - Fork 0
/
state.go
123 lines (114 loc) · 3.56 KB
/
state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package multiclusterapp
import (
"context"
"fmt"
"github.com/rancher/norman/condition"
"github.com/rancher/types/apis/management.cattle.io/v3"
pv3 "github.com/rancher/types/apis/project.cattle.io/v3"
"github.com/rancher/types/config"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"strings"
)
//StartMCAppStateController gets all corresponding apps and update condition on multi cluster app sync
func StartMCAppStateController(ctx context.Context, management *config.ManagementContext) {
mcApps := management.Management.MultiClusterApps("")
s := &MCAppStateController{
Apps: management.Project.Apps("").Controller().Lister(),
MultiClusterApps: mcApps,
}
mcApps.AddHandler(ctx, "multi-cluster-app-state-controller", s.sync)
}
type MCAppStateController struct {
Apps pv3.AppLister
MultiClusterApps v3.MultiClusterAppInterface
}
func (m *MCAppStateController) sync(key string, mcapp *v3.MultiClusterApp) (runtime.Object, error) {
if mcapp == nil || mcapp.DeletionTimestamp != nil {
return mcapp, nil
}
if v3.MultiClusterAppConditionInstalled.IsUnknown(mcapp) && v3.MultiClusterAppConditionInstalled.GetMessage(mcapp) == "upgrading" {
return mcapp, nil
}
var apps []*pv3.App
for _, t := range mcapp.Spec.Targets {
split := strings.SplitN(t.ProjectName, ":", 2)
if len(split) != 2 {
return mcapp, fmt.Errorf("error in splitting project ID %v", t.ProjectName)
}
projectNS := split[1]
if t.AppName != "" {
app, err := m.Apps.Get(projectNS, t.AppName)
if err != nil {
if errors.IsNotFound(err) {
logrus.Infof("app %s not found for mcapp %s in projectNS %s", t.AppName, mcapp.Name, projectNS)
continue
}
return mcapp, err
}
if value, ok := app.Labels[MultiClusterAppIDSelector]; !ok || value != mcapp.Name {
return mcapp, fmt.Errorf("app %s missing label selector for %s", t.AppName, mcapp.Name)
}
apps = append(apps, app)
}
}
toUpdate := mcapp.DeepCopy()
if len(apps) != len(mcapp.Spec.Targets) {
if !v3.MultiClusterAppConditionInstalled.IsUnknown(toUpdate) {
v3.MultiClusterAppConditionInstalled.Unknown(toUpdate)
return m.MultiClusterApps.Update(toUpdate)
}
return mcapp, nil
}
updating := map[string]bool{}
installing := map[string]bool{}
for _, app := range apps {
if !pv3.AppConditionInstalled.IsTrue(app) {
installing[app.Name] = true
} else if !pv3.AppConditionDeployed.IsTrue(app) {
updating[app.Name] = true
}
}
if checkForUpdate(installing, toUpdate, v3.MultiClusterAppConditionInstalled) {
return m.MultiClusterApps.Update(toUpdate)
}
if checkForUpdate(updating, toUpdate, v3.MultiClusterAppConditionDeployed) {
return m.MultiClusterApps.Update(toUpdate)
}
return mcapp, nil
}
func checkForUpdate(transitioning map[string]bool, mcapp *v3.MultiClusterApp, cond condition.Cond) bool {
if len(transitioning) > 0 {
existing := strings.Split(cond.GetMessage(mcapp), ",")
if !Equal(existing, transitioning) {
cond.Unknown(mcapp)
cond.Message(mcapp, GetMsg(transitioning))
return true
}
} else if !cond.IsTrue(mcapp) {
cond.True(mcapp)
cond.Reason(mcapp, "")
cond.Message(mcapp, "")
return true
}
return false
}
func GetMsg(data map[string]bool) string {
var keys []string
for key := range data {
keys = append(keys, key)
}
return fmt.Sprintf("%s", strings.Join(keys, ","))
}
func Equal(existing []string, toUpdate map[string]bool) bool {
if len(existing) != len(toUpdate) {
return false
}
for _, name := range existing {
if _, ok := toUpdate[name]; !ok {
return false
}
}
return true
}